自定义实体 ID 数据类型在插入时失败

发布于 2025-01-18 18:28:00 字数 3877 浏览 0 评论 0原文

我正在尝试在数据层中使用顺序int ids,并使用 hashids.nets.net < /a>库在我的服务器代码和UI层中给我类似YouTube的“ Hashed” ID。我通过创建下面显示的自定义struct来使它起作用我想。然后,我会在任何数据列属性使用此数据类型时自动创建valueConverter onModeLcreating

最终,与查询对象无处可完美地工作,包括外键等。但是,仅在尝试插入新对象时,我也会在下面显示错误。我的目标是让实体框架忽略hashiDentifier inserts上的值,如果其值为默认。如果值为0,它也会忽略int。我希望数据库使用Identity我设置在此处,然后使用valueeconverter我设置的实体框架来生成新密钥我的hashientifier的形式,在插入以外的所有其他情况下都可以使用。

public partial struct HashIdentifier : IEquatable<HashIdentifier>, IEquatable<int>, IComparable<HashIdentifier>, IComparable<int>
{
    private static Hashids _hashids = new("seed", 11);

    private int _value;

    public int Value => _value;

    public HashIdentifier(in int value)
    {
        _value = value;
    }

    public override string ToString()
    {
        return _hashids.Encode(Value);
    }

    public static HashIdentifier Parse(in string value)
    {
        if (TryParse(value, out HashIdentifier _result))
            return _result;
        throw new InvalidIdentifierException(value);
    }

    public static bool TryParse(in string value, out HashIdentifier result)
    {
        int[] _decode = _hashids.Decode(value);

        if (_decode.Length == 0)
        {
            result = default;
            return false;
        }
        result = new(_decode[0]);
        return true;
    }

    public int CompareTo(HashIdentifier other)
    {
        return CompareTo(other.Value);
    }

    public int CompareTo(int other)
    {
        return Value.CompareTo(other);
    }

    public override bool Equals(object obj)
    {
        switch (obj)
        {
            case int _a: return Equals(_a);
            case HashIdentifier _a: return Equals(_a);
        }
        return false;
    }

    public bool Equals(int other)
    {
        return other == Value;
    }

    public bool Equals(HashIdentifier other)
    {
        return other.Value == Value;
    }

    public static bool operator ==(int left, HashIdentifier right)
    {
        return right.Equals(left);
    }

    public static bool operator !=(int left, HashIdentifier right)
    {
        return !(left == right);
    }

    public static explicit operator int(HashIdentifier value)
    {
        return value.Value;
    }

    public static explicit operator HashIdentifier(int value)
    {
        return new(value);
    }
}

我插入的错误:

当SIDENTITY_INSERT设置为OFF

hashindentifier时,在表'testtable'中的身份列的明确值 0 有效。它确实在达到异常之前,确实会访问valueConverter。那么,为什么它认为我要设定一个明确的价值呢?

这不是

我已经搜索Internet和Stackoverflow的解决方案的副本,但我还没有找到解决方案。我是不是正在寻找一种使用Identity_insert的方法。请仔细了解我的问题。我希望实体框架能够像切换键使用自定义结构之前一样工作。

我的表格架构如下:

CREATE TABLE [dbo].[TestTable]
(
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Sequence] [int] NULL,
    [CreatedDate] [datetime] NOT NULL

    CONSTRAINT [PK_TestTable] 
        PRIMARY KEY CLUSTERED ([Id] ASC)
                WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                      IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                      ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

更新

这似乎是一个已知问题,根据 Microsoft文档

当前具有转换的密钥属性无法使用生成的键值。投票 github问题#11597 要删除此限制。

I'm trying to use sequential INT ids in my data layer and use the Hashids.NET library to give me YouTube-like 'hashed' ids in my server code and UI layers. I got it to work by creating the custom struct shown below which resides in memory as an Int32 and prints to string as a hashed id exactly as I want. I then automatically create a ValueConverter in OnModelCreating any time any data column property uses this data type.

This ends up working flawlessly with querying objects, includes, foreign keys, etc. However, only upon trying to insert new objects, I get the error also shown below. My goal is to get Entity Framework to ignore the HashIdentifier value on inserts if its value is default. The same way it would ignore an int if the value is 0. I want the database to be generating the new keys with the IDENTITY I set there, and then Entity Framework to use the ValueConverter I have set up to use the new values in the form of my HashIdentifier, which already works in every other case other than inserts.

public partial struct HashIdentifier : IEquatable<HashIdentifier>, IEquatable<int>, IComparable<HashIdentifier>, IComparable<int>
{
    private static Hashids _hashids = new("seed", 11);

    private int _value;

    public int Value => _value;

    public HashIdentifier(in int value)
    {
        _value = value;
    }

    public override string ToString()
    {
        return _hashids.Encode(Value);
    }

    public static HashIdentifier Parse(in string value)
    {
        if (TryParse(value, out HashIdentifier _result))
            return _result;
        throw new InvalidIdentifierException(value);
    }

    public static bool TryParse(in string value, out HashIdentifier result)
    {
        int[] _decode = _hashids.Decode(value);

        if (_decode.Length == 0)
        {
            result = default;
            return false;
        }
        result = new(_decode[0]);
        return true;
    }

    public int CompareTo(HashIdentifier other)
    {
        return CompareTo(other.Value);
    }

    public int CompareTo(int other)
    {
        return Value.CompareTo(other);
    }

    public override bool Equals(object obj)
    {
        switch (obj)
        {
            case int _a: return Equals(_a);
            case HashIdentifier _a: return Equals(_a);
        }
        return false;
    }

    public bool Equals(int other)
    {
        return other == Value;
    }

    public bool Equals(HashIdentifier other)
    {
        return other.Value == Value;
    }

    public static bool operator ==(int left, HashIdentifier right)
    {
        return right.Equals(left);
    }

    public static bool operator !=(int left, HashIdentifier right)
    {
        return !(left == right);
    }

    public static explicit operator int(HashIdentifier value)
    {
        return value.Value;
    }

    public static explicit operator HashIdentifier(int value)
    {
        return new(value);
    }
}

The error I get on inserts:

Cannot insert explicit value for identity column in table 'TestTable' when IDENTITY_INSERT is set to OFF

The value of the HashIdentifier at the time of the insert was effectively 0. And it does call into the ValueConverter right before hitting the exception. So why does it think I am setting an explicit value?

This is not a duplicate

I've already searched the internet and StackOverflow for solutions and I haven't found one. I am not looking for a way to use IDENTITY_INSERT. Please understand my issue carefully. I want Entity Framework to work as it did before I switched my keys to use custom structs.

My table schema is as follows:

CREATE TABLE [dbo].[TestTable]
(
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Sequence] [int] NULL,
    [CreatedDate] [datetime] NOT NULL

    CONSTRAINT [PK_TestTable] 
        PRIMARY KEY CLUSTERED ([Id] ASC)
                WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                      IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                      ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

Update

This appears to be a known issue according to the Microsoft Documentation

Currently key properties with conversions cannot use generated key values. Vote for GitHub issue #11597 to have this limitation removed.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文