我正在尝试更多地了解Linq查询和实体框架(4.1).请查看以下两个查询.两个查询都返回汽车类型名称(CarType.Name)
在第一个查询中,我使用了join并忽略了导航属性CarType
from c in Cars.AsEnumerable().
Where(e => e.CarId == Guid.Parse("0501cc96-5610-465d-bafc-16b30890c224"))
join ct in CarTypes on c.CarTypeId equals ct.CarTypeId
select new CarType {
Name = ct.Name
}
Run Code Online (Sandbox Code Playgroud)
第二,我使用了导航属性CarType
from c in Cars.AsEnumerable()
where c.CarId == Guid.Parse("0501cc96-5610-465d-bafc-16b30890c224")
select new CarType {
Name = c.CarType.Name
}
Run Code Online (Sandbox Code Playgroud)
我在LinqPad中运行了两个,因此有Guid.Parse函数.
当我运行这些时,第一个语句运行得更快.LinqPad报告00:00:036.第二个语句运行较慢,LinqPad报告00:00:103
看看结果似乎Linq查询使用连接而不是导航属性更快.真的是这样吗?请有人对此表示赞赏.在编写Linq查询时,是否有任何一般指导,我应该遵循的最佳实践?
谢谢
linq optimization navigational-properties entity-framework-4.1
我的EF模型的一部分看起来像这样:

摘要:
现在,我正试图实现的查询:
获取有关位置ID 1234的信息,包括与这些讨论相关的任何讨论和评论.
我可以得到讨论和这样的评论:
var discussions = ctx.Posts
.OfType<Discussion>()
.Include(x => x.Comments)
.ToList();
Run Code Online (Sandbox Code Playgroud)
但我似乎无法根据位置实体上的帖子导航获取它.
我试过这个:
var locationWithDiscussionsAndComments = ctx
.Locations
.Include(x => x.Posts
.OfType<Discussion>()
.Select(y => y.Comments))
.SingleOrDefault();
Run Code Online (Sandbox Code Playgroud)
哪个编译,但我得到错误:
System.ArgumentException:包含路径表达式必须引用实体定义的属性,也可以引用嵌套属性或对Select的调用.参数名称:路径
有任何想法吗?我可能会从帖子中"倒退":
var locationWithDiscussionsAndComments = ctx
.Posts
.Include(x => x.Location)
.OfType<Discussion>()
.Include(x => x.Comments)
.Where(x => x.LocationId == 1234)
.Select(x => x.Location)
.ToList();
Run Code Online (Sandbox Code Playgroud)
但就我的存储库而言,这在毛发和语义上都是错误的(我不应该通过帖子库来获取有关位置的信息).
有任何想法吗?
编辑
因此,在对它进行更大的思考之后,我意识到这OfType<T>是一个过滤操作.据我们所知,EF不支持使用预先加载进行过滤.唯一的选择是检索所有内容,或使用匿名类型投影.
我无法检索所有内容,因为涉及的元数据太多了.所以我正在尝试匿名类型投影.
c# abstract-class eager-loading navigational-properties entity-framework-ctp5
我们正在使用实体框架代码优先,我遇到了在我们不希望的情况下尝试回滚插入,更新和删除实体更改的问题SaveChanges().
具体来说,我有一个datagridview,我用它作为TableEditor,来更改一些辅助表.datagridview绑定到DbSet<TEntity>.
我的回滚更新似乎工作正常,我只是将currentValues设置回其OriginalValues,并将状态更改为unchanged.
当一个记录插入到gridview中(但没有保存更改)时,它永远不会出现在实体类中,我再也看不到了......所以我猜它不会进入dbSet,也没有回滚是需要这个吗?
但我的主要问题在于删除:
根据我的理解,当记录被"删除"(例如tableData.Remove(currentItem);)时,它被简单标记为删除,直到调用SaveChanges.因此,如果我将状态从deleted返回更改为unchanged,那应该处理回滚,对吧?
那么,记录确实再次显示,但记录的导航属性已经消失!(即包含外键的列和与其他实体的必需关系).为什么是这样??!
这是我到目前为止:
public void RollbackChanges(DbEntityEntry entry)
{
if (entry.State == EntityState.Modified)
{
foreach (var propertyName in entry.OriginalValues.PropertyNames)
{
entry.CurrentValues[propertyName] = entry.OriginalValues[propertyName];
}
entry.State = EntityState.Unchanged;
}
else if (entry.State == EntityState.Deleted)
{
entry.State = EntityState.Unchanged;
}
else if ((entry.State == EntityState.Added) || (entry.State == EntityState.Detached))
{
MessageBox.Show("I don't think this ever happens?");
}
}
Run Code Online (Sandbox Code Playgroud)
用法示例:
foreach (var entity …Run Code Online (Sandbox Code Playgroud) 考虑以下实体模型:
public class Parent
{
public virtual FirstChild FirstChild { get; set; }
public virtual SecondChild SecondChild { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在我的代码中,我加载了Parent实体:
Parent parent = <loaded in some way>;
Run Code Online (Sandbox Code Playgroud)
要显式加载其导航属性,我使用
db.Entry(parent).Reference(p => p.FirstChild).Load();
db.Entry(parent).Reference(p => p.SecondChild).Load();
Run Code Online (Sandbox Code Playgroud)
但这会导致两个数据库查询。
问题:有没有更优雅的方式,允许在单个查询中显式加载多个导航属性?
如果我没有parent加载,我会立即加载:
Parent parent = db.Parents
.Include(p => p.FirstChild)
.Include(p => p.SecondChild)
.FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)
但是,正如我所提到的,我已经在没有相关实体的情况下加载了它(并且我无法修改加载代码)。