Помочь linqtosql datacontext использовать неявное преобразование между столбцом varchar в базе данных и таблицей и пользовательским типом данных в моем приложении - PullRequest
0 голосов
/ 01 мая 2010

Я создаю таблицу базы данных mssql "Orders", которая будет содержать поле varchar (50), "Value", содержащее строку, представляющую слегка сложный тип данных, "OrderValue".

Я использую класс linqtosql datacontext, который автоматически вводит столбец «Значение» в виде строки.

Я дал операторы неявного преобразования класса 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», а не как «string». Тогда я смогу избежать сложного кода и переписать вышеизложенное как:

// 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 запутывается и выдает ошибку.

Могу ли я что-нибудь сделать, чтобы не запутаться и неявно преобразовать?

Ответы [ 2 ]

1 голос
/ 01 мая 2010

Интересная проблема ... Мне удалось это сделать, расширив сгенерированный частичный класс контекста данных. Там я создал отдельный «типизированный» объект, который устанавливается при загрузке исходных данных и заменяет исходные данные при сохранении ...

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

}
0 голосов
/ 24 мая 2013

Имея подобную проблему и используя отражатель, я решил, что могу предоставить публичный статический метод 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
}

Это использует .NET 4.5; Я не уверен, существует ли эта поддержка метода "Parse" в предыдущем System.Data.Linq или нет.

...