- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我尝试在 C# 集合上遵守 DDD 原则 see more here
而且我注意到初始种子 HasData 的模型构建器方法依赖于 ICollection 的添加方法。当从数据库更新/迁移过程中调用该方法时,有什么方法可以规避或欺骗该方法?
到目前为止,我为欺骗它所做的一切都遵循这条路径。
1) 在名为 ReadOnlyKollection
的 ICollection 周围创建一个包装器2) 在模型上有一个私有(private)的 ICollection,以避免将集合暴露给外界。
3) 公开包装器,使过时的 Add 和一些其他方法在使用时会抛出 NotImplementedException。
然而,尽管有过时的警告,仍然可以使用 Add 方法,因为它仍然是公共(public)的,并且需要更新/迁移数据库过程中使用的种子 HasData 方法。
我正在考虑至少限制从包装类的 Add 方法内部调用方法。
当 HasData 运行并且只允许此方法处理并为任何其他方法抛出异常时,我可能很高兴知道调用成员。
请注意,CallerMethodName 编译类型功能不能使用,因为这会破坏 ICollectoion 接口(interface)协定。
有什么想法可以避免遵循 DDD 原则将私有(private)集合属性暴露给 Entity Framework ? (并且仍然有 HasData 方法的增强来更新/迁移数据库过程)。请参阅下面的一些代码..
public interface IReadOnlyKollection<T> : ICollection<T>
{
}
public class ReadOnlyKollection<T> : IReadOnlyKollection<T>
{
private readonly ICollection<T> _collection;
public ReadOnlyKollection(ICollection<T> collection)
{
_collection = collection;
}
public int Count => _collection.Count;
public bool IsReadOnly => _collection.IsReadOnly;
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<T> GetEnumerator() => _collection.GetEnumerator();
public bool Contains(T item) => _collection.Contains(item);
public void CopyTo(T[] array, int arrayIndex) => _collection.CopyTo(array, arrayIndex);
[Obsolete]
public void Add(T item) => _collection.Add(item); // CallerMethodName trick to be applied here or ??
[Obsolete]
public void Clear() => throw new NotImplementedException();
[Obsolete]
public bool Remove(T item) => throw new NotImplementedException();
}
public class StateProvince
{
public StateProvince() //EF Constructor
{
}
public StateProvince(string id, string name)
: this(name)
{
Id = id;
}
public string Id { get; protected set; }
public string Name { get; protected set; }
public string CountryRegionId { get; protected set; }
public virtual CountryRegion CountryRegion { get; protected set; }
}
public class CountryRegion
{
public CountryRegion() //EF Constructor
{
}
public CountryRegion(string id, string name)
: this(name)
{
Id = id;
}
public string Id { get; protected set; }
public string Name { get; protected set; }
private readonly ICollection<StateProvince> _stateProvinces = new List<StateProvince>(); // Private collection for DDD usage
public IReadOnlyKollection<StateProvince> StateProvinces => new ReadOnlyKollection<StateProvince>(_stateProvinces); // Public like read only collection public immutable exposure
}
EntityTypeBuilder<StateProvince> // Code reduced for brevity
builder.HasIndex(e => e.CountryRegionId);
builder.Property(e => e.Id).IsUnicode(false).HasMaxLength(3).ValueGeneratedNever();
builder.Property(e => e.CountryRegionId).IsRequired().IsUnicode(false).HasMaxLength(3);
builder.Property(e => e.Name).IsRequired().HasMaxLength(50);
EntityTypeBuilder<CountryRegion> builder // Code reduced for brevity
builder.Property(e => e.Id).IsUnicode(false).HasMaxLength(3).ValueGeneratedNever();
builder.Property(e => e.Name).IsRequired().HasMaxLength(50);
builder.HasMany(e => e.StateProvinces)
.WithOne(e => e.CountryRegion)
.HasForeignKey(e => e.CountryRegionId)
.IsRequired()
.OnDelete(DeleteBehavior.Restrict);
builder.HasData(GetData())
private static object[] GetData()
{
return new object[]
{
new { Id = "AF", Name = "Afghanistan", IsDeleted = false, LastModified = DateTimeOffset.UtcNow },
new { Id = "AL", Name = "Albania", IsDeleted = false, LastModified = DateTimeOffset.UtcNow },
new { Id = "DZ", Name = "Algeria", IsDeleted = false, LastModified = DateTimeOffset.UtcNow },
new { Id = "AS", Name = "American Samoa", IsDeleted = false, LastModified = DateTimeOffset.UtcNow },
最佳答案
链接的帖子是针对 EF6 的,而 HasData
方法表示 EF Core。在 EF Core 中,事情要简单得多,在这方面不需要任何技巧。
EF Core 不需要 ICollection<T>
用于集合导航属性。任何公共(public)属性(property)返回IEnumerable<T>
或派生接口(interface)/类按照惯例作为集合导航属性被发现。因此,您可以安全地将您的收藏公开为 IEnumerable<T>
, IReadOnlyCollection<T>
, IReadOnlyList<T>
等等
EF Core 不需要属性 setter ,因为它可以配置为使用 backing field直接。
此外,不需要特殊的“EF 构造函数”,因为 EF Core 支持 constructors with parameters .
话虽如此,您不需要自定义集合接口(interface)/类。示例模型可能是这样的:
public class CountryRegion
{
public CountryRegion(string name) => Name = name;
public CountryRegion(string id, string name) : this(name) => Id = id;
public string Id { get; protected set; }
public string Name { get; protected set; }
private readonly List<StateProvince> _stateProvinces = new List<StateProvince>(); // Private collection for DDD usage
public IReadOnlyCollection<StateProvince> StateProvinces => _stateProvinces.AsReadOnly(); // Public like read only collection public immutable exposure
}
public class StateProvince
{
public StateProvince(string name) => Name = name;
public StateProvince(string id, string name) : this(name) => Id = id;
public string Id { get; protected set; }
public string Name { get; protected set; }
public string CountryRegionId { get; protected set; }
public virtual CountryRegion CountryRegion { get; protected set; }
}
并添加以下内容(最简单 - 对于所有实体的所有属性)
modelBuilder.UsePropertyAccessMode(PropertyAccessMode.Field);
或 CountryRegion
的所有属性
builder.UsePropertyAccessMode(PropertyAccessMode.Field);
或者只是为了那个导航属性
builder.HasMany(e => e.StateProvinces)
.WithOne(e => e.CountryRegion)
.HasForeignKey(e => e.CountryRegionId)
.IsRequired()
.OnDelete(DeleteBehavior.Restrict)
.Metadata.PrincipalToDependent.SetPropertyAccessMode(PropertyAccessMode.Field);
仅此而已。您将能够使用所有 EF Core 功能,例如 Include
/ThenInclude
,在 LINQ to Entities 查询中“导航”等(包括 HasData
)。支持字段允许 EF Core 在需要时添加/删除元素,甚至替换整个集合(如果该字段不是只读的)。
关于c# - 避免将私有(private)集合属性暴露给 Entity Framework 。 DDD原则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55172288/
你能比较一下属性吗 我想禁用文本框“txtName”。有两种方式 使用javascript,txtName.disabled = true 使用 ASP.NET, 哪种方法更好,为什么? 最佳答案 我
Count 属性 返回一个集合或 Dictionary 对象包含的项目数。只读。 object.Count object 可以是“应用于”列表中列出的任何集合或对
CompareMode 属性 设置并返回在 Dictionary 对象中比较字符串关键字的比较模式。 object.CompareMode[ = compare] 参数
Column 属性 只读属性,返回 TextStream 文件中当前字符位置的列号。 object.Column object 通常是 TextStream 对象的名称。
AvailableSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。 object.AvailableSpace object 应为 Drive 
Attributes 属性 设置或返回文件或文件夹的属性。可读写或只读(与属性有关)。 object.Attributes [= newattributes] 参数 object
AtEndOfStream 属性 如果文件指针位于 TextStream 文件末,则返回 True;否则如果不为只读则返回 False。 object.A
AtEndOfLine 属性 TextStream 文件中,如果文件指针指向行末标记,就返回 True;否则如果不是只读则返回 False。 object.AtEn
RootFolder 属性 返回一个 Folder 对象,表示指定驱动器的根文件夹。只读。 object.RootFolder object 应为 Dr
Path 属性 返回指定文件、文件夹或驱动器的路径。 object.Path object 应为 File、Folder 或 Drive 对象的名称。 说明 对于驱动器,路径不包含根目录。
ParentFolder 属性 返回指定文件或文件夹的父文件夹。只读。 object.ParentFolder object 应为 File 或 Folder 对象的名称。 说明 以下代码
Name 属性 设置或返回指定的文件或文件夹的名称。可读写。 object.Name [= newname] 参数 object 必选项。应为 File 或&
Line 属性 只读属性,返回 TextStream 文件中的当前行号。 object.Line object 通常是 TextStream 对象的名称。 说明 文件刚
Key 属性 在 Dictionary 对象中设置 key。 object.Key(key) = newkey 参数 object 必选项。通常是 Dictionary 
Item 属性 设置或返回 Dictionary 对象中指定的 key 对应的 item,或返回集合中基于指定的 key 的&
IsRootFolder 属性 如果指定的文件夹是根文件夹,返回 True;否则返回 False。 object.IsRootFolder object 应为&n
IsReady 属性 如果指定的驱动器就绪,返回 True;否则返回 False。 object.IsReady object 应为 Drive&nbs
FreeSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。只读。 object.FreeSpace object 应为 Drive 对象的名称。
FileSystem 属性 返回指定的驱动器使用的文件系统的类型。 object.FileSystem object 应为 Drive 对象的名称。 说明 可
Files 属性 返回由指定文件夹中所有 File 对象(包括隐藏文件和系统文件)组成的 Files 集合。 object.Files object&n
我是一名优秀的程序员,十分优秀!