sil*_*der 12 c# orm relationship entity-framework-core asp.net-core
我正在试图弄清楚如何处理本文档中描述的"单一导航属性案例" :
假设我们有2个型号.
class School
{
public ICollection<Child> Childrens {get; set;}
...
}
Run Code Online (Sandbox Code Playgroud)
和
class Child
{
public int Id {get; set;}
...
}
Run Code Online (Sandbox Code Playgroud)
所以它是由约定创建的多对一关系,没有明确的外键Child
.
所以问题是我们是否有Child
实例并知道School.Id
有没有办法更新这种关系,而无需额外调用数据库来获取School
实例.
Iva*_*oev 13
所以问题是我们是否有
Child
实例并知道School.Id
有没有办法更新这种关系,而无需额外调用数据库来获取School
实例.
是的,这是可能的.您可以创建一个假的存根 School
实体实例与Id
而已,Attach
它的DbContext
(这种方式告诉EF,它是现有的),Attach
该Child
实例出于同样的原因,然后添加Child
到父集合,并呼吁SaveChanges
:
Child child = ...;
var schoolId = ...;
var school = new School { Id = schoolId };
context.Attach(school);
context.Attach(child);
school.Childrens.Add(child);
context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)
更新:实际上还有另一种清洁方式,因为即使实体没有导航或FK属性,EF Core也允许您访问/修改所谓的阴影属性
阴影属性是实体类中不存在的属性.这些属性的值和状态仅在Change Tracker中维护.
一旦你知道这个名字.在您的情况下,没有配置将按惯例"SchoolId"
.
因此,不需要伪School
实体实例,只需确保Child
附加,然后通过ChangeTracker API简单地设置shadow属性:
context.Attach(child);
context.Entry(child).Property("SchoolId").CurrentValue = schoolId;
context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)
不,没有任何方法可以通过使用 ORM 和 ORM 提供的强类型来做到这一点,无需
SchoolId
在Child
)执行原始查询(这击败了使用 ORM 实现强类型的想法),同时与数据库无关
// Bad!! Database specific dialect, no strong typing
ctx.Database.ExecuteSqlCommandAsync("UPDATE Childs SET schoolId = {0}", schoolId);
Run Code Online (Sandbox Code Playgroud)当您选择使用 ORM 时,您必须接受相关 ORM 框架的某些技术限制。
如果您想遵循领域驱动设计(DDD)并从实体中删除所有数据库特定字段,那么将域模型用作实体并不容易。
DDD 和 ORM 没有很好的协同作用,对此有更好的方法,但需要不同的架构方法(即:CQRS+ES(带有事件源的命令查询职责分离)。
这对于 DDD 效果更好,因为来自 EventSourcing 的事件只是简单(且不可变)的消息类,可以将其作为序列化 JSON 存储在数据库中并重播以重建域实体的状态。但这是另一回事了,人们可以就这个主题写一整本书。
Child
如果您的对象是父级的导航属性/“反向引用” ,则上述场景仅在单个数据库操作中可能出现。
class School
{
public ICollection<Child> Childrens {get; set;}
...
}
Run Code Online (Sandbox Code Playgroud)
和
class Child
{
public int Id {get; set;}
// this is required if you want do it in a single operation
public int SchoolId { get; set; }
// this one is optional
public School { get; set; }
...
}
Run Code Online (Sandbox Code Playgroud)
然后你可以做类似的事情:
ctx.Childs.Add(new Child { Id = 7352, SchoolId = 5, ... });
Run Code Online (Sandbox Code Playgroud)
当然,你首先必须知道学校 ID 并知道它是有效的,否则如果SchoolId
是无效值,操作将抛出异常,所以我不推荐这种方法。
如果您只有一个childId
而不添加一个全新的孩子,您仍然必须先获得孩子。
// childId = 7352
var child = ctx.Childs.FirstOrDefault(c => c.Id == childId);
// or use ctx.Childs.Find(childId); if there is a chance that
// some other operation already loaded this child and it's tracked
// schoolId = 5 for example
child.SchoolId = schoolId;
ctx.SaveChanges();
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
8637 次 |
最近记录: |