请假设这个架构:
public class Mammal
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Dog : Mammal
{
public int TailId { get; set; }
public Tail Tail { get; set; }
}
public class Bat : Mammal
{
public int WingId { get; set; }
public Wing Wing { get; set; }
}
public class Buffalo : Mammal
{
public virtual ICollection<Horn> Horns { get; set; }
}
public class Tail
{
public int Id { get; set; }
...
}
public class Wing
{
public int Id { get; set; }
...
}
public class Horn
{
public int Id { get; set; }
...
}
现在,我的背景:
public class MyContext : DbContext
{
public DbSet<Mammal> Mammals { get; set; }
}
所以,我想只进行一次SQL查询,并包含(并加载)所有嵌套实体,如:
var query = myContext.Mammals
.IncludeIfTypeIs<Dog>(d => d.Tail)
.IncludeIfTypeIs<Bat>(b => b.Wing)
.IncludeIfTypeIs<Buffalo>(b => b.Horns)
...
...
;
我知道我可以单独执行此操作,但我不想要,因为我有很多实体,我需要最小化数据库请求。
我不想使用延迟加载,因为这也会产生许多数据库请求。
如何实现?
答案 0 :(得分:0)
你可以尝试这样的事情:
public static string SearchPage(Uri url, int timeOutSeconds)
{
StringBuilder sb = new StringBuilder();
try
{
string place = HttpUtility.ParseQueryString(url.Query).Get("destination").Split(':')[1];
string resultID = HttpUtility.ParseQueryString(url.Query).Get("resultID");
string checkin = HttpUtility.ParseQueryString(url.Query).Get("checkin").Replace("-", "");
string checkout = HttpUtility.ParseQueryString(url.Query).Get("checkout").Replace("-", "");
string Rooms = HttpUtility.ParseQueryString(url.Query).Get("Rooms");
string adults_1 = HttpUtility.ParseQueryString(url.Query).Get("adults_1");
string languageCode = "EN";
string currencyCode = "INR";
string ck = "languageCode=" + languageCode + "; a_aid=400; GcRan=1; __RequestVerificationToken=IHZjc7KM_LbUXRypz02LoK4wmeLNcmRpIr-6vmPl5eNepILScAc15vn0TgQJtmABgedDy8xz4bnkqC30_zUGE1A1SaA1; Analytics=LandingID=place:77469:0m&LanguageCode=" + languageCode + "&WebPageID=9; Tests=165F000901000A1100F81000FE110100000102100103100104000105100052; dcid=dal05; currencyCode=" + currencyCode + "; countryCode=" + languageCode + "; search=place:" + place + "#" + checkin + "#" + checkout + "#" + adults_1 + "; SearchHistory=" + place + "%" + checkin + "%" + checkout + "%" + adults_1 + "%" + currencyCode + "%%11#" + place + "%" + checkin + "%" + checkout + "%" + adults_1 + "%" + currencyCode + "%%" + resultID + "#; visit=date=2015-11-23T18:26:05.4922127+11:00&id=45111733-acef-47d1-aed3-63cef1a60591; visitor=id=efff4190-a4a0-41b5-b807-5d18e4ee6177&tracked=true";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = timeOutSeconds * 1000;
request.ReadWriteTimeout = timeOutSeconds * 1000;
request.KeepAlive = true;
request.Method = "GET";
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
request.UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36 OPR/33.0.1990.115";
request.Headers.Add("Accept-Language", "en-US,en;q=0.8");
request.Headers.Add("Cookie", ck);
request.Headers.Add("Upgrade-Insecure-Requests", "1");
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream());
string line = reader.ReadToEnd();
sb.Append(line);
sb.Replace("<br/>", Environment.NewLine);
sb.Replace("\n", Environment.NewLine);
sb.Replace("\t", " ");
reader.Close();
reader.Dispose();
request.Abort();
}
catch (Exception ex)
{
//throw ex;
}
return sb.ToString();
}
然后在你的数据库调用中:
public static class Extensions
{
public static IQueryable<Mammal> IncludeExtraEntities<Mammal,T>(this IQueryable<Mammal> query, T derivedType) where T :Mammal
{
if (derivedType is Dog)
return query.Include("Tail");
if (derivedType is Bat)
return query.Include("Wing");
return query;
}
}
也许这会奏效。
答案 1 :(得分:0)
您可以创建一个方法来包含表达式列表。 (或者可能是一种扩展方法)。
public static IQueryable<Mammal> GetMammals(params Expression<Func<T, Object>>[] includeExps)
{
var query = context.Mammals.AsQueryable();
if (includeExps != null)
query = includeExps.Aggregate(query, (current, exp) => current.Include(exp));
return query;
}
然后,在你的代码中:
//Bat and Dog will be included here
var mammals = GetMammals(i => i.Bat, i => i.Dog);
希望它有所帮助!
答案 2 :(得分:0)
问题是,如何仅使用基类的DbSet并且不使用延迟加载来加载派生类型的属性?我担心这是不可能的。
但你可以这样做:
public class MyContext : DbContext
{
public DbSet<Mammal> Mammals { get; set; }
public DbSet<Dog> Dogs { get; set; }
public DbSet<Bat> Bats { get; set; }
}
您还可以简单地为每种类型实现一种特定于类型的方法
public static class Extensions
{
public static IQueryable<Dog> IncludeExtraEntities<Dog>(this IQueryable<Dog> query) where Dog : Mammal
{
return query.Include("Tail");
}
public static IQueryable<Bat> IncludeExtraEntities<Bat>(this IQueryable<Bat> query) where Bat: Mammal
{
return query.Include("Wing");
}
}
然后,您只需致电:
myContext.Dogs.IncludeExtraEntities();
将调用取决于您的类型的方法。
答案 3 :(得分:0)
你对Include
的期望太高了。您在Include
中输入的lambda表达式只是一个看起来太聪明的字符串提供程序。在引擎盖下,解析其成员表达式以获取属性的名称,这就是全部。该名称将输入到接受字符串参数的Include
方法中。该方法可以完成实际工作。
lambda表达式必须指向IQueryable
中类型的导航属性。你做不到......
myContext.Mammals.Include(d => d.Tail)
...因为Tail
不是基本类型的属性。你只能做......
myContext.Mammals.OfType<Dog>().Include(d => d.Tail)
你能得到的最好的东西就像是
from m in context.Mammals
let tail = (m as Dog).Tail
let wing = (m as Bat).Wing
let horns= (m as Buffalo).Horns
select new { Mammal = m, tail, wing, horns }
由于所有内容都已转换为SQL,因此您无需担心空引用异常。
答案 4 :(得分:0)
我遇到了类似的问题,在这里我是如何解决的:
public IEnumerable<OrderLine> GetAllOrderLinesData()
{
var _StockOrderLines = appContext.OrderLines.OfType<StockOrderLine>()
.Include(p => p.Order).Include(p => p.Product);
var _AnnualOrderLines = appContext.OrderLines.OfType<AnnualOrderLine>()
.Include(p => p.Order).Include(p => p.Customer);
return _StockOrderLines.ToList<OrderLine>().Union<OrderLine>(_AnnualOrderLines.ToList<OrderLine>());
}
你可以改变你的课程 :)
答案 5 :(得分:0)
EF Core在2.1及更高版本中支持此功能。参见Github问题here
var query = myContext.Mammals
.Include(d => (d as Dog).Tail)
.Include(b => (b as Bat).Wing)
.Include(b => (b as Buffalo).Horns)
这将在一个查询中包含所有属性。
此处是指向official documentation的链接。