使用下面的简单示例,使用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创建自己的类,并在选择中指定该类型?或者还有其他更简单的方法吗?
如果主要的想法是让SQL选择语句发送到数据库服务器只有必需的字段,而不是所有的实体字段,那么你可以这样做:
public class Class1
{
public IList<Car> getCarsByProjectionOnSmallNumberOfProperties()
{
try
{
//Get the SQL Context:
CompanyPossessionsDAL.POCOContext.CompanyPossessionsContext dbContext
= new CompanyPossessionsDAL.POCOContext.CompanyPossessionsContext();
//Specify the Context of your main entity e.g. Car:
var oDBQuery = dbContext.Set<Car>();
//Project on some of its fields, so the created select statment that is
// sent to the database server, will have only the required fields By making a new anonymouse type
var queryProjectedOnSmallSetOfProperties
= from x in oDBQuery
select new
{
x.carNo,
x.eName,
x.aName
};
//Convert the anonymouse type back to the main entity e.g. Car
var queryConvertAnonymousToOriginal
= from x in queryProjectedOnSmallSetOfProperties
select new Car
{
carNo = x.carNo,
eName = x.eName,
aName = x.aName
};
//return the IList<Car> that is wanted
var lst = queryConvertAnonymousToOriginal.ToList();
return lst;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
throw;
}
}
}
在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包。
如果你在你的数据库中有一个关系设置,在BreedId上有一个外键约束,你还没有得到吗?
所以我现在可以调用:
internal Album GetAlbum(int albumId)
{
return Albums.SingleOrDefault(a => a.AlbumID == albumId);
}
在调用它的代码中:
var album = GetAlbum(1);
foreach (Photo photo in album.Photos)
{
[...]
}
在你的实例中,你会调用像dog。breed。breedname这样的东西-正如我说的,这依赖于你的数据库是用这些关系建立的。
正如其他人所提到的,如果存在数据库调用问题,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;
}
必须首先使用ToList()方法从数据库中获取行,然后选择项作为类。
试试这个:
public partial class Dog {
public string BreedName { get; set; }}
List<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
}).ToList()
.Select(x=>
new Dog{
Name = x.Name,
BreedName = x.BreedName,
}).ToList();
return result;}
因此,诀窍首先是ToList()。它是立即进行查询并从数据库中获取数据。第二个技巧是选择项并使用对象初始化器生成加载项的新对象。
希望这能有所帮助。