Как сохранить несколько столбцов базы данных в массив с Linq2Sql - PullRequest
1 голос
/ 07 января 2010

Мне нужно работать с несколькими таблицами SQL Server, которые обычно выглядят так:

int id_this, int id_that, ..., double Value1, double Value2, ..., double Value96

Я знаю, что это отстой, но я не могу изменить это.Теперь я хочу определить некоторый класс, например

public class Foo
{
    public int Id_This { get; set; }
    public int Id_That { get; set; }
    ...
    public double Value[];
}

. Массив-значение, конечно, является свойством, но я думаю, вы поняли.

Вопрос в том, какчтобы получить 96 столбцов в массиве настолько безболезненно, насколько это возможно.

Я мог бы сделать это с простым SqlDataReader, поскольку DataRow разрешает индексированный доступ, но мне интересно, могу ли я объявить некоторые атрибуты или написать некоторый минимальный объем кодаиспользовать класс напрямую с LINQ2SQL.

Как минимум, я хотел бы сделать

dataContext.ExecuteQuery<Foo>("SELECT * FROM Foo");

1 Ответ

2 голосов
/ 07 января 2010

Ох, это ... мило? Методы DataContext всегда ожидают тип объекта; нет ExecuteReader, что является болью (но понятно, так как она хочет вести себя как ORM). Если честно, я бы соблазнился использовать ADO.NET для смелости этой таблицы, но если вы сопоставили широкую таблицу с DataContext, вы сможете использовать обычный C # или рефлексию.

Поскольку число не меняется, если у вас нет нескольких таблиц, я просто укушу пулю и напишу некрасивый код:

Foo foo = new Foo { Id_This = obj.Id_This, Id_That = obj.Id_That,
    Values = new double[] {obj.Value1, obj.Value2, ... } };

Если у вас несколько таблиц ... отражение, возможно, оптимизированное с помощью Expression:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
class FooUgly
{
    public int IdThis { get; set; }
    public int IdThat { get; set; }
    public double Value1 { get; set; }
    public double Value2 { get; set; }
    public double Value3 { get; set; }
}
class Foo
{
    public int IdThis { get; set; }
    public int IdThat { get; set; }
    public double[] Values { get; set; }
    public Foo() { }
    internal Foo(FooUgly ugly)
    {
        IdThis = ugly.IdThis;
        IdThat = ugly.IdThat;
        Values = extractor(ugly);
    }
    // re-use this!!!
    static readonly Func<FooUgly, double[]> extractor =
        ValueExtractor<FooUgly, double>.Create("Value", 1, 3);
}
static class Program
{
    static void Main()
    {
        FooUgly ugly = new FooUgly { IdThis = 1, IdThat = 2, Value1 = 3, Value2 = 4, Value3 = 5 };
        Foo foo = new Foo(ugly);
    }
}
static class ValueExtractor<TFrom,TValue>
{
    public static Func<TFrom, TValue[]> Create(string memberPrefix, int start, int end)
    {
        if(end < start) throw new ArgumentOutOfRangeException();
        ParameterExpression param = Expression.Parameter(typeof(TFrom), "source");
        List<Expression> vals = new List<Expression>();
        for(int i = start ; i <= end ; i++) {
            vals.Add(Expression.PropertyOrField(param, memberPrefix + i));
        }
        Expression arr = Expression.NewArrayInit(typeof(TValue), vals);
        return Expression.Lambda<Func<TFrom, TValue[]>>(arr, param).Compile();
    }
}
...