我正在尝试了解如何使用Entity Framework 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;
}
答案 0 :(得分:2)
由于这些调用,您确实对数据库进行了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
}
一些注意事项:
null
值的可能性,您可以将它们考虑在内using left joins with DefaultIfEmpty
。答案 1 :(得分:1)
您应该设置原始外键值,而不是设置对象引用。从面向对象的角度来看,这听起来像是一个异端,但它是实体框架推荐的方法,有效地设置关联。
当然,首先应该设置外键值。在您的VehicleStateLogEntryDbo
中,这可能如下所示:
public int VehicleIdentifier { get; set; } // or guid?
[ForeignKey("VehicleIdentifier")]
public VehicleDbo Vehicle { get; set }
ForeignKey
属性告诉EF两个属性都属于外键关联。这也可以通过流畅的API配置,例如在OnModelCreating
覆盖:
modelbuilder.Entry<VehicleStateLogEntryDbo>()
.HasRequired(v => v.Vehicle)
.WithMany()
.HasForeignKey(v => v.VehicleIdentifier);
顺便说一下,只有Vehicle
属性被称为独立关联。
因此,当您拥有这些外键关联时,您只需设置FK值即可。也许您应该修改您的DTO以转移这些值而不是名称等。