Id được gõ mạnh trong Lõi khung thực thể


12

Tôi đang cố gắng để có một Idlớp học được đánh máy mạnh mẽ , hiện đang giữ 'dài' trong nội bộ. Thực hiện dưới đây. Vấn đề tôi gặp phải khi sử dụng điều này trong các thực thể của mình là Entity Framework cho tôi một thông báo rằng Id thuộc tính đã được ánh xạ lên nó. Xem IEntityTypeConfigurationdưới đây của tôi .

Lưu ý: Tôi không hướng đến việc thực hiện DDD cứng nhắc. Vì vậy, hãy ghi nhớ điều này khi bình luận hoặc trả lời . Toàn bộ id đằng sau bản đánh máy Idlà dành cho các nhà phát triển đến dự án mà họ mạnh mẽ sử dụng Id trong tất cả các thực thể của họ, tất nhiên được dịch thành long(hoặc BIGINT) - nhưng sau đó thì rõ ràng cho những người khác.

Bên dưới lớp & cấu hình, không hoạt động. Repo có thể được tìm thấy tại https://github.com/KodeFoxx/Kf.CleanArch architectureTemplate.NetCore31 ,

Idtriển khai lớp (đã bị đánh dấu lỗi thời, vì tôi đã từ bỏ ý tưởng cho đến khi tôi tìm thấy giải pháp cho việc này)

namespace Kf.CANetCore31.DomainDrivenDesign
{
    [DebuggerDisplay("{DebuggerDisplayString,nq}")]
    [Obsolete]
    public sealed class Id : ValueObject
    {
        public static implicit operator Id(long value)
            => new Id(value);
        public static implicit operator long(Id value)
            => value.Value;
        public static implicit operator Id(ulong value)
            => new Id((long)value);
        public static implicit operator ulong(Id value)
            => (ulong)value.Value;
        public static implicit operator Id(int value)
            => new Id(value);


        public static Id Empty
            => new Id();

        public static Id Create(long value)
            => new Id(value);

        private Id(long id)
            => Value = id;
        private Id()
            : this(0)
        { }

        public long Value { get; }

        public override string DebuggerDisplayString
            => this.CreateDebugString(x => x.Value);

        public override string ToString()
            => DebuggerDisplayString;

        protected override IEnumerable<object> EquatableValues
            => new object[] { Value };
    }
}

EntityTypeConfigurationTôi đã sử dụng khi Id không được đánh dấu lỗi thời cho thực thểPerson Tuy nhiên, thật không may, khi loại Id, EfCore không muốn ánh xạ nó ... khi loại dài thì không có vấn đề gì ... như các loại thuộc sở hữu khác, như bạn thấy (với Name) làm việc tốt

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);
        }
    }

Entity lớp cơ sở (khi tôi vẫn đang sử dụng Id, vì vậy khi nó không được đánh dấu lỗi thời)

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;
    }
}

Person(tên miền và tài liệu tham khảo cho ValueObjects khác có thể được tìm thấy tại https://github.com/KodeFoxx/Kf.CleanArchitectureTemplate.NetCore31/tree/master/Source/Core/Domain/Kf.CANetCore31.Core.Domain/People )

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);
    }
}

Câu trả lời:


3

Tôi không hướng đến việc thực hiện DDD cứng nhắc. Vì vậy, hãy ghi nhớ điều này khi bình luận hoặc trả lời. Toàn bộ id đằng sau Id được nhập là dành cho các nhà phát triển đến dự án mà họ đã gõ mạnh để sử dụng Id trong tất cả các thực thể của họ

Vậy thì tại sao không chỉ thêm một bí danh:

using Id = System.Int64;

Chắc chắn, tôi thích ý tưởng. Nhưng bất cứ khi nào bạn sẽ sử dụng "Id" trong tệp .cs, bạn sẽ không phải đảm bảo đặt câu lệnh này bằng cách sử dụng câu lệnh đó lên trên cùng - trong khi với một lớp được truyền qua, người ta không phải làm thế? Ngoài ra, tôi sẽ mất chức năng lớp cơ sở khác như Id.Empty..., hoặc sẽ phải triển khai nó theo cách khác trong một phương thức mở rộng sau đó ... Tôi thích ý tưởng này, thx để suy nghĩ cùng. Nếu không có giải pháp nào khác được đưa ra, tôi sẽ giải quyết vấn đề này, vì điều này nêu rõ ý định.
Yves Schelpe

3

Vì vậy, sau khi tìm kiếm một lúc lâu, và cố gắng để có thêm câu trả lời, tôi đã tìm thấy nó, đây là lúc đó. Cảm ơn Andrew Lock.

ID được gõ mạnh trong EF Core: Sử dụng ID thực thể được gõ mạnh để tránh nỗi ám ảnh nguyên thủy - Phần 4 : https://andrewlock.net/strongly-typed-ids-in-ef-core-USE-strongly-typed-entity- ids-to-tránh-primitive-obsession-part-4 /

TL; DR / Tóm tắt về Andrew Trong bài đăng này, tôi mô tả một giải pháp sử dụng ID được gõ mạnh trong các thực thể EF Core của bạn bằng cách sử dụng các trình biến đổi giá trị và IValueConverterSelector tùy chỉnh. ValueConverterSelector cơ sở trong khung EF Core được sử dụng để đăng ký tất cả các chuyển đổi giá trị tích hợp giữa các loại nguyên thủy. Bằng cách xuất phát từ lớp này, chúng tôi có thể thêm các trình chuyển đổi ID được gõ mạnh vào danh sách này và nhận chuyển đổi liền mạch trong các truy vấn EF Core của chúng tôi


2

Tôi nghĩ rằng bạn đã hết may mắn. Trường hợp sử dụng của bạn là cực kỳ hiếm. Và EF Core 3.1.1 vẫn đang vật lộn với việc đưa SQL vào cơ sở dữ liệu không bị hỏng trong bất kỳ trường hợp nào ngoại trừ các trường hợp cơ bản nhất.

Vì vậy, bạn sẽ phải viết một cái gì đó đi qua cây LINQ và đây có thể là một khối lượng công việc khổng lồ, và nếu bạn vấp phải lỗi trên EF Core - điều mà bạn sẽ - vui vẻ giải thích điều đó trong vé của bạn.


Tôi đồng ý trường hợp sử dụng là hiếm, nhưng ý tưởng đằng sau nó không hoàn toàn ngu ngốc tôi có thể hy vọng ...? Nếu vậy, xin vui lòng cho tôi biết. Nếu nó là ngu ngốc (bị thuyết phục cho đến nay thì không, vì các id được gõ mạnh rất dễ lập trình trong miền) hoặc nếu tôi không tìm thấy câu trả lời nhanh chóng, tôi có thể sử dụng một bí danh theo đề xuất của David Browne - micrososft bên dưới ( stackoverflow .com / a / 60155275/1155847 ). Cho đến nay rất tốt đối với các trường hợp sử dụng khác, và các bộ sưu tập và trường ẩn trong EF Core, không có lỗi, vì vậy tôi nghĩ nó thật lạ, vì nếu không thì tôi có trải nghiệm tốt với sản phẩm.
Yves Schelpe

Nó không phải là ngu ngốc, nhưng điều hiếm thấy là tôi chưa từng thấy hỗ trợ nó và EfCore tệ đến mức ngay bây giờ tôi đang làm việc để gỡ bỏ nó và quay trở lại Ef (không phải cốt lõi) bởi vì tôi cần phải vận chuyển. Đối với tôi EfCore 2.2 hoạt động tốt hơn - 3.1 là 100% không thể tin được vì bất kỳ phép chiếu nào tôi sử dụng đều dẫn đến sql xấu hoặc "chúng tôi không đánh giá phía khách hàng nữa" ngay cả khi - 2.2 hoàn toàn đánh giá trên máy chủ. Vì vậy, tôi sẽ không mong đợi họ dành thời gian cho những thứ như vậy - trong khi các chức năng cốt lõi của họ bị hỏng. github.com/dotnet/efcore/issues/19830#issuecomment-584234667 để biết thêm chi tiết
TomTom

EfCore 3.1 bị hỏng, có nhiều lý do khiến nhóm EfCore quyết định không đánh giá phía khách hàng nữa, họ thậm chí còn đưa ra cảnh báo về điều đó trong 2.2 để chuẩn bị cho bạn những thay đổi sắp tới. Về điều đó, tôi không thấy rằng điều đặc biệt đó đã bị phá vỡ. Đối với những thứ khác tôi không thể nhận xét, tôi đã thấy các vấn đề, nhưng có thể giải quyết chúng mà không phải trả bất kỳ chi phí hoàn hảo nào. Mặt khác, trong 3 dự án gần đây nhất tôi đã thực hiện để sản xuất 2 trong số đó là dựa trên Dapper, một dựa trên Ef ... Có lẽ tôi nên đặt mục tiêu đi theo con đường nhỏ hơn cho dự án này, nhưng đánh bại mục đích dễ dàng cho các nhà phát triển mới :-)... Chúng ta sẽ thấy.
Yves Schelpe

Vấn đề là định nghĩa của đánh giá phía máy chủ là gì. Họ thậm chí thổi vào những thứ rất đơn giản mà làm việc hoàn hảo. Xé toạc chức năng cho đến khi nó là usele. Chúng tôi chỉ cần xóa EfCore và quay lại EF. EF + bên thứ 3 cho lfiltering toàn cầu = làm việc. Vấn đề với dapper là tôi cho phép mọi người dùng phức tạp quyết định LINQ - Tôi PHẢI dịch từ bo sang truy vấn phía máy chủ. Làm việc trong Ef 2.2, bây giờ hoàn toàn bị cấm.
TomTom

Ok, bây giờ tôi đã đọc github.com/dotnet/efcore/issues/19679#issuecomment-583650245 này ... Tôi hiểu ý bạn nói bạn đang sử dụng lib của bên thứ ba nào? Bạn có thể viết lại những gì bạn nói về Dapper không, vì tôi không hiểu ý của bạn. Đối với tôi nó đã hoạt động, nhưng đó là những dự án có khóa thấp chỉ có 2 nhà phát triển trong nhóm - và rất nhiều bản tóm tắt thủ công để viết để làm cho nó hoạt động hiệu quả tất nhiên ...
Yves Schelpe
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.