C# 实体框架核心中的强类型Ids
我试图创建一个强类型的C# 实体框架核心中的强类型Ids,c#,entity-framework,.net-core,entity-framework-core,domain-driven-design,C#,Entity Framework,.net Core,Entity Framework Core,Domain Driven Design,我试图创建一个强类型的Id类,它现在在内部保存“long”。执行情况如下。 我在实体中使用它的问题是,实体框架给我一个消息,说明属性Id已经映射到它了。请参见下面我的IEntityTypeConfiguration 注意:我的目标不是严格的DDD实现。所以在评论或回答时请记住这一点。类型化的id背后的整个id是为进入项目的开发人员准备的,他们是强类型的,在他们的所有实体中使用id,当然被翻译成long(或BIGINT)-但是其他人很清楚 在类和配置下面,这不起作用。 回购协议可在 Idclas
Id
类,它现在在内部保存“long”。执行情况如下。
我在实体中使用它的问题是,实体框架给我一个消息,说明属性Id已经映射到它了。请参见下面我的IEntityTypeConfiguration
注意:我的目标不是严格的DDD实现。所以在评论或回答时请记住这一点。类型化的id
背后的整个id是为进入项目的开发人员准备的,他们是强类型的,在他们的所有实体中使用id,当然被翻译成long
(或BIGINT
)-但是其他人很清楚
在类和配置下面,这不起作用。
回购协议可在
class at(现在已注释掉):Id
和实体
类(其中对于值对象
而言,实体
属性的类型为Id
.cs(如上所述):Id
- 配置位于:
Id
类实现(现在标记为过时,因为在找到解决方案之前我放弃了这个想法)
实体
基类(当我还在使用Id时,所以当它没有被标记为过时时)
我的目标不是要有一个严格的DDD实现。所以在评论或回答时请记住这一点。类型化id后面的整个id是给来项目的开发人员的,他们是强类型的,在他们的所有实体中使用id
那么为什么不添加一个类型别名呢:
using Id = System.Int64;
我认为你运气不好。你的用例非常罕见。EF Core 3.1.1仍在努力将SQL添加到数据库中,除了最基本的用例外,数据库中没有任何损坏
所以,你必须写一些经过LINQ树的东西,这可能是一个巨大的工作量,如果你在EF Core上偶然发现bug,你会很高兴在你的罚单中解释它。所以在搜索了很长一段时间后,试图得到更多的答案,我找到了,就在这里。感谢Andrew Lock EF Core中的强类型ID:使用强类型实体ID避免原始困扰-第4部分: TL;安德鲁博士/总结
在这篇文章中,我介绍了一种在EF核心实体中使用强类型ID的解决方案,方法是使用值转换器和自定义的IValueConverterSelector。EF核心框架中的基值转换器Selector用于注册基本类型之间的所有内置值转换。通过从该类派生,我们可以将强类型ID添加到转换到此列表,并在整个EF核心查询过程中实现无缝转换当然,我喜欢这个想法。但每次您都会使用“Id”在一个.cs文件中,您是否必须确保将这个using语句放在上面?当传递一个类时,您不必这样做?而且我将丢失其他基类功能,例如
Id.Empty
..,或者必须在扩展方法中实现它…我喜欢这个想法,thx供您考虑。如果没有其他解决方案出现,我会满足于此,因为这清楚地表明了目的。我同意用例是罕见的,但它背后的想法并不完全愚蠢,我希望…?如果是,请让我知道。如果它愚蠢(到目前为止还不确信,因为强类型ID在域中很容易编程),或者如果我不能很快找到答案,我可能会使用下面David Browne-Micrososft建议的别名().到目前为止,其他用例、集合和EF Core中的隐藏字段都很好,没有bug,所以我觉得这很奇怪,因为我对该产品有很好的体验。这本身并不愚蠢,但很少有enoug,因为我从未见过支持它的orm,EfCore太差了,所以我现在正在努力删除它并将其移回to Ef(非核心),因为我需要发货。对我来说,EfCore 2.2工作得更好-3.1是100%不可用的,因为我使用的任何投影都会导致糟糕的sql或“我们不再评估客户端”即使-2.2在服务器上进行了完美的评估。所以,我不希望他们在核心功能被破坏的情况下花时间在这样的事情上。更详细地说,对于3.1被破坏的情况,EfCore团队决定不再评估客户端是有原因的,他们甚至在2.2中发出警告,让您为即将到来的更改做好准备或者说,我看不出这件事有什么问题。至于其他我不能评论的东西,我也看到了问题,但我能够在没有任何性能成本的情况下解决它们。另一方面,在我为生产做的最后3个项目中,其中2个是基于整洁的,一个基于环境足迹的……也许我应该为这一个选择整洁的路线,但却击败了pu新开发人员轻松入门的用途:-)。。。我们拭目以待。问题是什么是服务器端评估的定义。他们甚至吹嘘一些非常简单的东西,这些东西可以完美地工作。删除功能,直到它被使用。我们只需删除EfCore并返回EF。EF+第三方进行全局过滤=工作。dapper的问题是,我允许每个复杂的用户决定LINQ-我必须将它从bo转换为服务器端查询。在EF2.2工作,现在完全瘫痪了。好吧,我现在读到这个。。。我明白你的意思了你在用什么第三方库?我不明白你的意思,你能把你所说的关于整洁的话改一改吗。对我来说,它是有效的,但它是一个低调的项目,团队中只有两个开发人员——当然,还有很多手动模板要编写,以使它高效地工作。。。
public sealed class PersonEntityTypeConfiguration
: IEntityTypeConfiguration<Person>
{
public void Configure(EntityTypeBuilder<Person> builder)
{
// this would be wrapped in either a base class or an extenion method on
// EntityTypeBuilder<TEntity> where TEntity : Entity
// to not repeated the code over each EntityTypeConfiguration
// but expanded here for clarity
builder
.HasKey(e => e.Id);
builder
.OwnsOne(
e => e.Id,
id => {
id.Property(e => e.Id)
.HasColumnName("firstName")
.UseIdentityColumn(1, 1)
.HasColumnType(SqlServerColumnTypes.Int64_BIGINT);
}
builder.OwnsOne(
e => e.Name,
name =>
{
name.Property(p => p.FirstName)
.HasColumnName("firstName")
.HasMaxLength(150);
name.Property(p => p.LastName)
.HasColumnName("lastName")
.HasMaxLength(150);
}
);
builder.Ignore(e => e.Number);
}
}
namespace Kf.CANetCore31.DomainDrivenDesign
{
/// <summary>
/// Defines an entity.
/// </summary>
[DebuggerDisplay("{DebuggerDisplayString,nq}")]
public abstract class Entity
: IDebuggerDisplayString,
IEquatable<Entity>
{
public static bool operator ==(Entity a, Entity b)
{
if (ReferenceEquals(a, null) && ReferenceEquals(b, null))
return true;
if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
return false;
return a.Equals(b);
}
public static bool operator !=(Entity a, Entity b)
=> !(a == b);
protected Entity(Id id)
=> Id = id;
public Id Id { get; }
public override bool Equals(object @object)
{
if (@object == null) return false;
if (@object is Entity entity) return Equals(entity);
return false;
}
public bool Equals(Entity other)
{
if (other == null) return false;
if (ReferenceEquals(this, other)) return true;
if (GetType() != other.GetType()) return false;
return Id == other.Id;
}
public override int GetHashCode()
=> $"{GetType()}{Id}".GetHashCode();
public virtual string DebuggerDisplayString
=> this.CreateDebugString(x => x.Id);
public override string ToString()
=> DebuggerDisplayString;
}
}
namespace Kf.CANetCore31.Core.Domain.People
{
[DebuggerDisplay("{DebuggerDisplayString,nq}")]
public sealed class Person : Entity
{
public static Person Empty
=> new Person();
public static Person Create(Name name)
=> new Person(name);
public static Person Create(Id id, Name name)
=> new Person(id, name);
private Person(Id id, Name name)
: base(id)
=> Name = name;
private Person(Name name)
: this(Id.Empty, name)
{ }
private Person()
: this(Name.Empty)
{ }
public Number Number
=> Number.For(this);
public Name Name { get; }
public override string DebuggerDisplayString
=> this.CreateDebugString(x => x.Number.Value, x => x.Name);
}
}
using Id = System.Int64;