这个EF6代码应该有查询吗?
本文关键字:查询 EF6 代码 这个 | 更新日期: 2023-09-27 18:08:45
我试图了解如何使用实体框架6。下面的代码可以工作。但是,对于一个写操作,它似乎有四个查询。五次分别访问数据库似乎是不对的。我想要一个数据库调用,根据需要向每个表添加适当的项。有没有更好的方法来做下面的代码?或者它真的在SaveChanges调用中执行单个数据库命中吗?
public bool Write(ILogEntry logEntry)
{
var log = logEntry as AssetStateLogEntry;
if (log == null) return false;
using (var db = _dbContextProvider.ConstructContext())
{
if (db != null)
{
var state = new VehicleStateLogEntryDbo
{
LogSource = db.LogSources.FirstOrDefault(l => l.Name == log.Source.ToString())
?? new LogSourceDbo {Name = log.Source.ToString()},
Message = log.Message,
TimeStamp = log.TimeStamp.ToUniversalTime(),
Vehicle = db.Vehicles.FirstOrDefault(v => v.Name == log.Asset.Name)
?? new VehicleDbo {Name = log.Asset.Name, VehicleIdentifier = log.Asset.ID},
VehicleState = db.VehicleStates.FirstOrDefault(v => v.Name == log.StateValue.ToString() && v.VehicleStateType.Name == log.StateType.ToString())
?? new VehicleStateDbo
{
Name = log.StateValue.ToString(),
VehicleStateType = db.VehicleStateCategories.FirstOrDefault(c => c.Name == log.StateType.ToString())
?? new VehicleStateTypeDbo {Name = log.StateType.ToString()},
}
};
db.VehicleStateLogEntrys.Add(state);
db.SaveChanges();
}
}
return true;
}
作为这些调用的结果,您确实对数据库进行了4次查询:
-
db.LogSources.FirstOrDefault
-
db.Vehicles.FirstOrDefault
-
db.VehicleStates.FirstOrDefault
-
db.VehicleStateCategories.FirstOrDefault
当您调用FirstOrDefault
时,LINQ查询被执行,因此,数据库被击中。
我不知道你的模式,但也许你可以将它们中的一些连接到一个LINQ查询中(至少Vehicles*
表似乎是相关的)。
编辑:使用OP
请求的连接的示例查询把下面的查询作为我建议的起点,你还没有提供你的实体,所以这只是给你一个想法:
from l in db.LogSources
join v in db.Vehicles on l.Asset.ID equals v.VehicleIdentifier
join vs in db.VehicleStates on vs.VehicleIdentifier equals v.VehicleIdentifier
where l.Name == log.Source.ToString()
&& v.Name == log.Asset.Name
&& vs.Name == log.StateValue.ToString()
&& vs.VehicleStateType.Name == log.StateType.ToString()
select new VehicleStateLogEntryDbo
{
LogSource = l,
Message = log.Message,
TimeStamp = log.TimeStamp.ToUniversalTime(),
Vehicle = s,
VehicleState = vs
}
注意事项:
- 正如@Gert建议的那样,你应该使用外键而不是整个对象引用。
- 我没有考虑
null
值在示例中的可能性,您可以使用左连接与DefaultIfEmpty
来考虑它们。
不应该设置对象引用,而应该设置原始外键值。从面向对象的角度来看,这听起来像是异端邪说,但当涉及到有效地设置关联时,它是实体框架推荐的方法。
当然,首先应该设置外键值。在VehicleStateLogEntryDbo
中,这可能看起来像:
public int VehicleIdentifier { get; set; } // or guid?
[ForeignKey("VehicleIdentifier")]
public VehicleDbo Vehicle { get; set }
ForeignKey
属性告诉EF两个属性属于一个外键关联。这也可以通过fluent API来配置,例如在OnModelCreating
override中:
modelbuilder.Entry<VehicleStateLogEntryDbo>()
.HasRequired(v => v.Vehicle)
.WithMany()
.HasForeignKey(v => v.VehicleIdentifier);
顺便说一下,只有Vehicle
属性被称为独立于的关联。因此,当您有这些外键关联时,您可以简单地设置FK值。也许你应该修改你的DTO来传输这些值,而不是名称等。