LinQ to SQL和CLR用户定义类型

时间:2009-04-23 10:05:40

标签: sql clr user-defined-types

我已根据我的博客条目在.Net 3.5中创建了用户定义类型:

http://jwsadlerdesign.blogspot.com/2009/04/this-is-how-you-register.html

使用SQL与nHibernate等技术时,这种方法很有效。

但是,当我尝试将我的LinQ映射到SQL类以使用此UDT(属性定义而不是XML)时,我将该属性设置为枚举。我无法让LinQ映射到这种类型。我尝试过Image,Binary,varchar和integer,所有这些似乎都会发出Invalid Cast错误。

特别是我得到错误'无法将类型'ISTD.InstallManager.Common.Classes.SQLUDTTargetType'的对象强制转换为'System.Byte []',任何想法或帮助将不胜感激。

詹姆斯。

1 个答案:

答案 0 :(得分:2)

更新:我最近自己遇到了这个问题,发现之前的解决方案还不完整。尽管所有文档都说过,但 可能会这样做,但有些痛苦。

为了您自己的方便,第一步是实现一些转换运算符:

public class MyUDT : INullable, IBinarySerialize
{
    // Class implementation would go here
    // ...

    public static explicit operator MyUDT(byte[] data)
    {
        using (MemoryStream stream = new MemoryStream(data))
        {
            using (BinaryReader reader = new BinaryReader(stream))
            {
                MyUDT result = new MyUDT();
                result.Read(reader);
                return result;
            }
        }
    }

    public static explicit operator byte[](MyUDT x)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            using (BinaryWriter writer = new BinaryWriter(ms))
            {
                x.Write(writer);
            }
            return ms.ToArray();
        }
    }
}

无论你如何声明属性,Linq to SQL仍然会拒绝给你UDT字段。所以你必须给它一个二进制字段。您不需要存储过程或任何自定义SQL,只需向表中添加计算列:

ALTER TABLE MyTable
ADD UDTField_Data AS CAST(UDTField AS varbinary(len))

其中 len 是您在 MaxByteSize 属性中定义的UDT。

现在您终于可以访问列数据了。您可能想要使用UDT作为新属性的返回类型,认为Linq to SQL将找到您的转换运算符并自动从字节数组转换;不要打扰。 Linq to SQL将决定它实际上是一个序列化的.NET对象,并发出一条消息,说明“输入流不是有效的二进制格式”。相反,您需要另一层间接:

private MyUDT udtField;

[Column(Name = "UDTField_Data", DbType = "varbinary(len)")]
private byte[] UdtFieldData
{
    get { return (byte[])udtField; }
    set { udtField = (MyUDT)value; }
}

public MyUDT UdtProperty
{
    get { return udtField; }
    set { udtField = value; }
}

一些注意事项,以明确这里发生了什么:

  • 实际字段数据( udtField )声明为UDT本身,而不是字节数组。这样做的原因是我们只希望在从数据库加载或保存到数据库时进行转换。如果每次访问它时都必须将字节数组转换为UDT,这不仅会损害性能,而且如果UDT声明任何可变字段,也会导致不一致。
  • 原始byte []属性( UdtFieldData )被声明为私有,因此使用者只能看到UDT本身。只要具有[Column]属性,Linq to SQL仍会读取它。
  • UdtFieldData 属性未声明存储属性。这很关键;如果您尝试使用UDT字段作为存储属性,则只会出现相同的类型转换错误。
  • 最后, UdtProperty 属性是消费者实际访问数据的方式。它们看起来像任何其他财产。

不幸的是,你必须跳过这么多箍才能让它发挥作用,但它确实有效。通过Linq表面设计师进行这种按摩可能会有困难,这只是我不使用它的几个原因之一;最好自己编写类,并在必要时使用SqlMetal帮助您。