使用下面的简单示例,使用Linq to SQL从多个表返回结果的最佳方法是什么?
说我有两张桌子:
Dogs: Name, Age, BreedId Breeds: BreedId, BreedName
我想用他们的狗归还所有的狗BreedName
.我应该让所有的狗使用这样的东西没有问题:
public IQueryableGetDogs() { 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 IQueryableGetDogsWithBreedNames() { 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; }
现在我意识到编译器不会让我返回一组匿名类型,因为它期待Dogs,但有没有办法在不创建自定义类型的情况下返回它?或者我是否必须创建自己的类DogsWithBreedNames
并在select中指定该类型?还是有另一种更简单的方法吗?
我倾向于采用这种模式:
public class DogWithBreed { public Dog Dog { get; set; } public string BreedName { get; set; } } public IQueryableGetDogsWithBreedNames() { 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; }
这意味着你有一个额外的类,但它编码快速简单,易于扩展,可重用和类型安全.
你可以返回匿名类型,但它真的不漂亮.
在这种情况下,我认为创建适当的类型会好得多.如果仅在包含该方法的类型中使用它,则将其设置为嵌套类型.
就个人而言,我希望C#获得"命名匿名类型" - 即与匿名类型相同的行为,但具有名称和属性声明,但就是这样.
编辑:其他人建议返回狗,然后通过属性路径等访问品种名称.这是一个非常合理的方法,但IME导致你以特定方式完成查询的情况,因为你想要的数据使用 - 当您返回时,元信息会丢失IEnumerable
- 查询可能期望您使用(比如说)Breed
而不是Owner
由于某些加载选项等,但如果您忘记并开始使用其他属性,您的应用程序可能会工作,但不如你原先设想的那样有效.当然,我可能会说垃圾,或过度优化等等......
只是为了增加我的两分钱:-)我最近学会了一种处理匿名对象的方法.它只能在面向.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 Client Profile".
不,你不能通过一些诡计返回匿名类型.
如果您没有使用C#,那么您将要查找的内容(返回多个没有具体类型的数据)称为元组.
有很多C#元组实现,使用这里显示的实现,你的代码将像这样工作.
public IEnumerable> 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 Tuple (d, b); return result; }
在呼叫网站上:
void main() { IEnumerable> dogs = GetDogsWithBreedNames(); foreach(Tuple tdog in dogs) { Console.WriteLine("Dog {0} {1}", tdog.param1.Name, tdog.param2.BreedName); } }
你可以这样做:
public System.Collections.IEnumerable 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.ToList(); }
必须首先使用ToList()
方法从数据库中获取行,然后选择项作为类.试试这个:
public partial class Dog { public string BreedName { get; set; }} ListGetDogsWithBreedNames(){ 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 }).ToList() .Select(x=> new Dog{ Name = x.Name, BreedName = x.BreedName, }).ToList(); return result;}
所以,首先ToList()
是诀窍.它立即进行查询并从数据库中获取数据.第二个技巧是选择项目并使用对象初始化程序生成包含项目的新对象.
希望这可以帮助.
在C#7中,您现在可以使用元组!...,这消除了创建类以返回结果的需要。
这是一个示例代码:
public List<(string Name, string BreedName)> 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 }.ToList(); return result.Select(r => (r.Name, r.BreedName)).ToList(); }
您可能需要安装System.ValueTuple nuget软件包。