帮助 linqtosql datacontext 在数据库和表中的 varchar 列与我的应用程序中的自定义数据类型之间使用隐式转换

发布于 2024-08-31 03:43:36 字数 2083 浏览 2 评论 0原文

我正在创建一个 mssql 数据库表“Orders”,它将包含一个 varchar(50) 字段“Value”,其中包含一个表示稍微复杂的数据类型“OrderValue”的字符串。

我正在使用 linqtosql datacontext 类,它自动将“Value”列键入为字符串。

我为“OrderValue”类提供了与字符串之间的隐式转换运算符,因此我可以轻松地对 linqtosql 类使用隐式转换,如下所示:

// get an order from the orders table
MyDataContext db = new MyDataContext();
Order order = db.Orders(o => o.id == 1);

// use implicit converstion to turn the string representation of the order
// value into the complex data type.
OrderValue value = order.Value;

// adjust one of the fields in the complex data type
value.Shipping += 10;

// use implicit conversion to store the string representation of the complex
// data type back in the linqtosql order object
order.Value = value;

// save changes
db.SubmitChanges();

但是,我真的希望能够告诉 linqtosql 类将此字段键入为“ OrderValue”而不是“字符串”。然后我就能够避免复杂的代码并将上面的内容重写为:

// get an order from the orders table
MyDataContext db = new MyDataContext();
Order order = db.Orders(o => o.id == 1);

// The Value field is already typed as the "OrderValue" type rather than as string.
// When a string value was read from the database table, it was implicity converted
// to "OrderValue" type.
order.Value.Shipping += 10;

// save changes
db.SubmitChanges();

为了实现这个预期目标,我查看了数据上下文设计器并选择了“订单”表的“值”字段。

然后,在属性中,我将“类型”更改为“global::MyApplication.OrderValue”。

“服务器数据类型”属性保留为“VarChar(50) NOT NULL”

项目构建没有错误。

但是,当从数据库表中读取数据时,出现以下错误消息:

Could not convert from type 'System.String' to type 'MyApplication.OrderValue'.
    at System.Data.Linq.DBConvert.ChangeType(Object value, Type type)
    at Read_Order(ObjectMaterializer`1 )
    at System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReader`2.MoveNext()
    at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
    at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
    at Example.OrdersProvider.GetOrders() 
    at ... etc

从堆栈跟踪中,我相信从表中读取数据时会发生此错误。当将字符串转换为自定义数据类型时,即使存在隐式转换运算符,DBConvert 类也会感到困惑并引发错误。

我能做些什么来帮助它不感到困惑并进行隐式转换吗?

I am creating an mssql database table, "Orders", that will contain a varchar(50) field, "Value" containing a string that represents a slightly complex data type, "OrderValue".

I am using a linqtosql datacontext class, which automatically types the "Value" column as a string.

I gave the "OrderValue" class implicit conversion operators to and from a string, so I can easily use implicit conversion with the linqtosql classes like this:

// get an order from the orders table
MyDataContext db = new MyDataContext();
Order order = db.Orders(o => o.id == 1);

// use implicit converstion to turn the string representation of the order
// value into the complex data type.
OrderValue value = order.Value;

// adjust one of the fields in the complex data type
value.Shipping += 10;

// use implicit conversion to store the string representation of the complex
// data type back in the linqtosql order object
order.Value = value;

// save changes
db.SubmitChanges();

However, I would really like to be able to tell the linqtosql class to type this field as "OrderValue" rather than as "string". Then I would be able to avoid complex code and re-write the above as:

// get an order from the orders table
MyDataContext db = new MyDataContext();
Order order = db.Orders(o => o.id == 1);

// The Value field is already typed as the "OrderValue" type rather than as string.
// When a string value was read from the database table, it was implicity converted
// to "OrderValue" type.
order.Value.Shipping += 10;

// save changes
db.SubmitChanges();

In order to achieve this desired goal, I looked at the datacontext designer and selected the "Value" field of the "Order" table.

Then, in properties, I changed "Type" to "global::MyApplication.OrderValue".

The "Server Data Type" property was left as "VarChar(50) NOT NULL"

The project built without errors.

However, when reading from the database table, I was presented with the following error message:

Could not convert from type 'System.String' to type 'MyApplication.OrderValue'.
    at System.Data.Linq.DBConvert.ChangeType(Object value, Type type)
    at Read_Order(ObjectMaterializer`1 )
    at System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReader`2.MoveNext()
    at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
    at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
    at Example.OrdersProvider.GetOrders() 
    at ... etc

From the stack trace, I believe this error is happening while reading the data from the table. When presented with converting a string to my custom data type, even though the implicit conversion operators are present, the DBConvert class gets confused and throws an error.

Is there anything I can do to help it not get confused and do the implicit conversion?

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

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

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

二智少女 2024-09-07 03:43:36

有趣的问题...我设法通过扩展生成的数据上下文部分类来做到这一点。在那里我创建了一个单独的“类型化”对象,该对象在加载原始数据时设置并在保存时替换原始数据...

namespace LinqSQLTest
{
    partial class DataClasses1DataContext
    {

    }

    partial class Order
    {
        public OrderValue TypedValue { get; set; }

        partial void OnLoaded()
        {
            TypedValue = this.Value;
        }

        partial void OnValidate(System.Data.Linq.ChangeAction action)
        {
            if (action == System.Data.Linq.ChangeAction.Insert ||
                action == System.Data.Linq.ChangeAction.Update)
            {
                if (TypedValue != null) Value = TypedValue;
            }
        }        
    }    
}

要使用它,您可以通过“TypedValue”属性访问您的“值” - 而不是理想的,但这是我能看到的唯一方法。

private void button1_Click(object sender, RoutedEventArgs e)
{
    DataClasses1DataContext dc = new DataClasses1DataContext();
    Order order = new Order();
    OrderValue value = new OrderValue();
    value.OrderID=22;
    value.OtherStuff="stuff";
    order.Value= value;
    dc.Orders.InsertOnSubmit(order);
    dc.SubmitChanges();

    var incomingOrder = dc.Orders.Where(x => x.ID == 32).FirstOrDefault();
    Console.WriteLine("ID: {0} \r\n Stuff: {1}", incomingOrder.TypedValue.OrderID, incomingOrder.TypedValue.OtherStuff);

    incomingOrder.TypedValue.OrderID += 10;
    dc.SubmitChanges();

    var incomingOrder2 = dc.Orders.Where(x => x.ID == 32).FirstOrDefault();
    Console.WriteLine("ID: {0} \r\n Stuff: {1}", incomingOrder2.TypedValue.OrderID, incomingOrder2.TypedValue.OtherStuff);

}

Interesting problem... I managed to do it by extending the generated data context partial class. In there I created a separate "typed" object which is set on load of the original data and replaces the original data on save...

namespace LinqSQLTest
{
    partial class DataClasses1DataContext
    {

    }

    partial class Order
    {
        public OrderValue TypedValue { get; set; }

        partial void OnLoaded()
        {
            TypedValue = this.Value;
        }

        partial void OnValidate(System.Data.Linq.ChangeAction action)
        {
            if (action == System.Data.Linq.ChangeAction.Insert ||
                action == System.Data.Linq.ChangeAction.Update)
            {
                if (TypedValue != null) Value = TypedValue;
            }
        }        
    }    
}

To use it, you'd access your "Value" through the "TypedValue" property instead - not ideal, but it's the only way I can see of doing it.

private void button1_Click(object sender, RoutedEventArgs e)
{
    DataClasses1DataContext dc = new DataClasses1DataContext();
    Order order = new Order();
    OrderValue value = new OrderValue();
    value.OrderID=22;
    value.OtherStuff="stuff";
    order.Value= value;
    dc.Orders.InsertOnSubmit(order);
    dc.SubmitChanges();

    var incomingOrder = dc.Orders.Where(x => x.ID == 32).FirstOrDefault();
    Console.WriteLine("ID: {0} \r\n Stuff: {1}", incomingOrder.TypedValue.OrderID, incomingOrder.TypedValue.OtherStuff);

    incomingOrder.TypedValue.OrderID += 10;
    dc.SubmitChanges();

    var incomingOrder2 = dc.Orders.Where(x => x.ID == 32).FirstOrDefault();
    Console.WriteLine("ID: {0} \r\n Stuff: {1}", incomingOrder2.TypedValue.OrderID, incomingOrder2.TypedValue.OtherStuff);

}
忆伤 2024-09-07 03:43:36

遇到类似的问题,并使用反射器,我确定可以提供一个名为 Parse 的公共静态方法,它采用字符串参数。如果类中存在 System.Data.Linq.DBConvert.ChangeType(object, Type) 将调用 Parse 方法。

因此,对于您的示例,添加到您的 OrderValue 类

public static OrderValue Parse(string source) {
    return new OrderValue().FromSourceString(source); // whatever you need to do to construct from the source
}

This is using .NET 4.5;我不确定以前的 System.Data.Linq 中是否存在这种“解析”方法支持。

Having a similar problem, and using reflector I determined that I could provide a public static method called Parse taking a string argument. The System.Data.Linq.DBConvert.ChangeType(object, Type) will call the Parse method if it exists in the class.

So for your example, add to your OrderValue class

public static OrderValue Parse(string source) {
    return new OrderValue().FromSourceString(source); // whatever you need to do to construct from the source
}

This is using .NET 4.5; I'm not sure if this "Parse" method support exists in previous System.Data.Linq or not.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文