使用下面的简单示例,使用Linq to SQL从多个表返回结果的最佳方法是什么?

假设我有两个表:

Dogs:   Name, Age, BreedId
Breeds: BreedId, BreedName

我想返回所有的狗与他们的育种名称。我应该让所有的狗使用这样的东西,没有问题:

public IQueryable<Dog> GetDogs()
{
    var db = new DogDataContext(ConnectString);
    var result = from d in db.Dogs
                 join b in db.Breeds on d.BreedId equals b.BreedId
                 select d;
    return result;
}

但如果我想要有品种的狗,并尝试这样做,我有问题:

public IQueryable<Dog> GetDogsWithBreedNames()
{
    var db = new DogDataContext(ConnectString);
    var result = from d in db.Dogs
                 join b in db.Breeds on d.BreedId equals b.BreedId
                 select new
                        {
                            Name = d.Name,
                            BreedName = b.BreedName
                        };
    return result;
}

现在我意识到编译器不让我返回一组匿名类型,因为它期待狗,但有没有一种方法来返回这个而不必创建一个自定义类型?或者我必须为DogsWithBreedNames创建自己的类,并在选择中指定该类型?或者还有其他更简单的方法吗?


当前回答

只是补充一下我的意见:-) 我最近学习了一种处理匿名对象的方法。它只能在针对。net 4框架时使用,并且只能在添加对System.Web.dll的引用时使用,但它非常简单:

...
using System.Web.Routing;
...

class Program
{
    static void Main(string[] args)
    {

        object anonymous = CallMethodThatReturnsObjectOfAnonymousType();
        //WHAT DO I DO WITH THIS?
        //I know! I'll use a RouteValueDictionary from System.Web.dll
        RouteValueDictionary rvd = new RouteValueDictionary(anonymous);
        Console.WriteLine("Hello, my name is {0} and I am a {1}", rvd["Name"], rvd["Occupation"]);
    }

    private static object CallMethodThatReturnsObjectOfAnonymousType()
    {
        return new { Id = 1, Name = "Peter Perhac", Occupation = "Software Developer" };
    }
}

为了能够添加对System.Web.dll的引用,你必须遵循rushonerok的建议:确保你的[项目的]目标框架是“。NET Framework 4“不是”。NET Framework 4客户端配置文件”。

其他回答

尝试这样获取动态数据。您可以转换List<>的代码

public object GetDogsWithBreedNames()
{
    var db = new DogDataContext(ConnectString);
    var result = from d in db.Dogs
                 join b in db.Breeds on d.BreedId equals b.BreedId
                 select new
                        {
                            Name = d.Name,
                            BreedName = b.BreedName
                        };
    return result.FirstOrDefault();
}

dynamic dogInfo=GetDogsWithBreedNames();
var name = dogInfo.GetType().GetProperty("Name").GetValue(dogInfo, null);
var breedName = dogInfo.GetType().GetProperty("BreedName").GetValue(dogInfo, null);

这并没有完全回答你的问题,但谷歌根据关键字引导我到这里。这是从列表中查询匿名类型的方法:

var anon = model.MyType.Select(x => new { x.Item1, x.Item2});

我倾向于这样的模式:

public class DogWithBreed
{
    public Dog Dog { get; set; }
    public string BreedName  { get; set; }
}

public IQueryable<DogWithBreed> GetDogsWithBreedNames()
{
    var db = new DogDataContext(ConnectString);
    var result = from d in db.Dogs
                 join b in db.Breeds on d.BreedId equals b.BreedId
                 select new DogWithBreed()
                        {
                            Dog = d,
                            BreedName = b.BreedName
                        };
    return result;
}

这意味着你有一个额外的类,但它是快速和容易编码,易于扩展,可重用和类型安全。

如果你要归还《Dogs》,你应该这样做:

public IQueryable<Dog> GetDogsWithBreedNames()
{
    var db = new DogDataContext(ConnectString);
    return from d in db.Dogs
           join b in db.Breeds on d.BreedId equals b.BreedId
           select d;
}

如果您希望Breed立即加载而不是延迟加载,只需使用适当的DataLoadOptions构造。

不能直接返回匿名类型,但可以通过泛型方法对它们进行循环。大多数LINQ扩展方法也是如此。这里没有什么神奇之处,虽然看起来它们会返回匿名类型。如果参数是匿名的结果也可以是匿名的。

var result = Repeat(new { Name = "Foo Bar", Age = 100 }, 10);

private static IEnumerable<TResult> Repeat<TResult>(TResult element, int count)
{
    for(int i=0; i<count; i++)
    {
        yield return element;
    }
}

下面是一个基于原始问题代码的示例:

var result = GetDogsWithBreedNames((Name, BreedName) => new {Name, BreedName });


public static IQueryable<TResult> GetDogsWithBreedNames<TResult>(Func<object, object, TResult> creator)
{
    var db = new DogDataContext(ConnectString);
    var result = from d in db.Dogs
                    join b in db.Breeds on d.BreedId equals b.BreedId
                    select creator(d.Name, b.BreedName);
    return result;
}