Настройка Linq для Sql DataContext - PullRequest
1 голос
/ 13 января 2009

Есть ли в любом случае простые способы добавить свойство в сгенерированную сущность Linq для Sql для ссылки на ее DataContext? Например:

var myContext = new DataContext(); 
var product = context.Products.Where(p => p.Id == productId).SingleOrDefault(); 

, а сущность продукта имеет свойство "Context" (product.Context), которое имеет ссылку на myContext, datacontext.

Я знаю, как настроить созданные объекты. Мой вопрос заключается в том, как настроить (я думаю, DataContext), чтобы установить свойство «Context» каждого экземпляра, который он создает для себя.

Я не уверен, что поступаю правильно или нет. Я хочу написать модель бизнес-инкапсуляции, которая имеет лучшую производительность при меньшем количестве кода. Пока я гуглил, я обнаружил, что объект DataContext очень легкий, и я подумал, что это будет хороший способ добавить экземпляр DataContext к каждому объекту. Это уменьшит необходимость присоединять отсоединенные объекты снова к новому экземпляру datacontext каждый раз, когда я хочу обновить или удалить их.

Если у вас есть другое решение, я буду очень признателен.

Спасибо

Ответы [ 6 ]

2 голосов
/ 13 января 2009

Есть ли простой способ добавить свойство к сгенерированному Sql объекту Linq для ссылки на его DataContext?

Нет простого способа добиться этого.

1 голос
/ 13 января 2009

См. Здесь: Определение исходного DataContext для запроса Linq to Sql

Я задал более или менее тот же вопрос. Вы можете получить контекст из IQueryable, который возвращает запрос linq to sql, но не из самой сущности, насколько я знаю.

1 голос
/ 13 января 2009

При этом вы побеждаете часть цели LINQ-to-SQL. Одна из целей - дать вам возможность работать с имеющимися у вас объектами, и вам не придется менять свой дизайн в зависимости от базы данных.

Прикрепляя DataContext к базе данных, вы связываете свое представление в коде со средствами его сохранения, что, как правило, является плохой идеей проектирования.

Если вы чувствуете, что должны сделать это, вы всегда можете наследовать от класса и затем реализовать интерфейс для этого класса, который предоставляет DataContext.

Я рекомендую реализовать интерфейс, поскольку вы не можете указать базовый класс конструктору LINQ-to-SQL и хотите, чтобы все ваши объекты имели общую реализацию.

0 голосов
/ 06 августа 2014

Вот пользовательская оболочка, которую я сделал для System.Data.Linq. Он содержит метод find, поэтому вместо вашего кода:

var myContext = new DataContext(); 
var product = context.Products.Where(p => p.Id == productId).SingleOrDefault();

Вы можете сделать это

var myContext = new DataContext(); 
var product = context.Products.Find(productId); //(assuming productId is your primary key)

Вы можете взять приведенный ниже код и выполнить любые пользовательские изменения, которые вы хотите установить product.Context, но это пример изменения DataContext.

Я также сделал методы сохранения и удаления. Вы заметите, что я перезаписываю запись, даже если она передается. Я делаю это, потому что запись может отделяться от контекста и не обновляться. Если кому-то нужен полный код, я могу опубликовать ссылку на github.

public abstract class DbContext : IDisposable
{
    #region Properties
    private string _connectionString { get; set; }
    private DataContext _context { get; set; }
    #endregion

    #region Constructor
    public DbContext(string connectionString)
    {
        _connectionString = connectionString;
        _context = new DataContext(_connectionString);
        Initialized(_context);
    }

    public DbContext(string server, string database, string userID, string password)
    {
        _connectionString = string.Format(
        "Server={0};Database={1};User Id={2};Password={3};MultipleActiveResultSets=true",
        server,
        database,
        userID,
        password);

        _context = new DataContext(_connectionString);
        Initialized(_context);
    }
    #endregion

    #region Methods
    /// <summary>
    /// Is used to get the contents of a Sql Server Table.
    /// </summary>
    /// <typeparam name="TEntity">Type</typeparam>
    /// <returns>Table</returns>
    public Table<TEntity> GetTable<TEntity, TPKType>()
        where TEntity : DbTableEquatable<IDbTableEquatable<TPKType>>
        where TPKType : struct
    {
        return _context.GetTable<TEntity>();
    }

    /// <summary>
    /// Is used to get the contents of a Sql Server Table.
    /// </summary>
    /// <typeparam name="TEntity">Type</typeparam>
    /// <returns>Table</returns>
    public Table<TEntity> GetTable<TEntity>()
        where TEntity : DbTableEquatable<IDbTableEquatable<long>>
    {
        return GetTable<TEntity, long>();
    }

    protected virtual void Initialized(DataContext context) { }

    /// <summary>
    /// Saves the changes to the database.  In order to save the table must inherit from DbTableEquatable 
    /// and be a type of IDbTableEquatable and the Primary Key Type must be a C# Structure
    /// </summary>
    /// <typeparam name="TEntity">Record Type</typeparam>
    /// <typeparam name="TPKType">Primary Key Type</typeparam>
    /// <param name="entity">Record</param>
    public virtual void SaveChanges<TEntity, TPKType>(TEntity entity)
        where TEntity : DbTableEquatable<IDbTableEquatable<TPKType>>
        where TPKType : struct
    {
        var changedList = _context.GetTable<TEntity>();
        var ID = entity.GetType().GetProperty("ID").GetValue(entity);

        _preprocessSave<TEntity, TPKType>(entity);

        // Save changes
        if (Convert.ToInt64(ID) == 0)
        {
            // Insert
            // If No ID we need to insert on submit
            _context.GetTable<TEntity>().InsertOnSubmit((TEntity)entity);
            _context.SubmitChanges();
        }
        else
        {
            // Update
            var item = changedList.Where(w => w.Equals(entity)).FirstOrDefault();
            ReflectionManager.SetValuesWithSkip(entity, item, "ID");
            _context.SubmitChanges();
        }

        Refresh();
    }

    /// <summary>
    /// Saves the changes to the database.  In order to save the Table the Record is from must inherit from DbTableEquatable 
    /// and be a type of IDbTableEquatable and the Primary Key Type must be a C# Structure
    /// </summary>
    /// <typeparam name="TEntity">Record Type</typeparam>
    /// <param name="entity">Record</param>
    public virtual void SaveChanges<TEntity>(TEntity entity)
        where TEntity : DbTableEquatable<IDbTableEquatable<long>>
    {
        SaveChanges<TEntity, long>(entity);
    }

    /// <summary>
    /// Saves any non committed changes to the database
    /// </summary>
    public void SaveChanges()
    {
        _context.SubmitChanges();
        Refresh();
    }

    /// <summary>
    /// Marks the record as delete and will be deleted when saved
    /// </summary>
    /// <typeparam name="TEntity">Record Type</typeparam>
    /// <typeparam name="TPKType">Primary Key Type</typeparam>
    /// <param name="entity">Record</param>
    public virtual void DeleteOnSave<TEntity, TPKType>(TEntity entity)
        where TEntity : DbTableEquatable<IDbTableEquatable<TPKType>>
        where TPKType : struct
    {
        var item = _context.GetTable<TEntity>().Where(w => w.Equals(entity)).FirstOrDefault();
        _context.GetTable<TEntity>().DeleteOnSubmit((TEntity)item);
    }

    /// <summary>
    /// Marks the record as delete and will be deleted when saved
    /// </summary>
    /// <typeparam name="TEntity">Record Type</typeparam>
    /// <param name="entity">Record</param>
    public virtual void DeleteOnSave<TEntity>(TEntity entity)
        where TEntity : DbTableEquatable<IDbTableEquatable<long>>
    {
        DeleteOnSave<TEntity, long>(entity);
    }

    protected virtual void _preprocessSave<TEntity, TPKType>(TEntity entity)
        where TEntity : DbTableEquatable<IDbTableEquatable<TPKType>>
        where TPKType : struct
    {

    }

    protected virtual void _preprocessSave<TEntity>(TEntity entity)
        where TEntity : DbTableEquatable<IDbTableEquatable<long>>
    {
        _preprocessSave<TEntity, long>(entity);
    }

    public void Dispose()
    {
        _connectionString = "";
        _context.Dispose();
        _context = null;
    }

    public virtual void Refresh<TEntity>(RefreshMode mode, TEntity entity) where TEntity : class
    {
        _context.Refresh(RefreshMode.OverwriteCurrentValues, entity);
    }

    public virtual void Refresh()
    {
        _context = new DataContext(_connectionString);
    }

    public virtual void Refresh<TEntity>(RefreshMode mode, params TEntity[] entities) where TEntity : class
    {
        _context.Refresh(RefreshMode.OverwriteCurrentValues, entities);
    }

    public virtual void Refresh<TEntity>(RefreshMode mode, IEnumerable<TEntity> entities) where TEntity : class
    {
        _context.Refresh(RefreshMode.OverwriteCurrentValues, entities);
    }
    #endregion
}

Extenstions

public static class Extension
{
    public static TEntity Find<TEntity, TPKType>(this Table<TEntity> table, TPKType ID, string pkName = "ID")
        where TEntity : DbTableEquatable<IDbTableEquatable<TPKType>>
        where TPKType : struct
    {
        TEntity copy = Activator.CreateInstance<TEntity>();

        // set value through reflection
        copy.GetType().GetProperty(pkName).SetValue(copy, ID, null);
        return (TEntity)table.Where(w => w.Equals(copy)).FirstOrDefault();
    }

    public static TEntity Find<TEntity>(this Table<TEntity> table, long ID, string pkName = "ID")
        where TEntity : DbTableEquatable<IDbTableEquatable<long>>
    {
        TEntity copy = Activator.CreateInstance<TEntity>();

        // set value through reflection
        copy.GetType().GetProperty(pkName).SetValue(copy, ID, null);
        return (TEntity)table.Where(w => w.Equals(copy)).FirstOrDefault();
    }
}

}

Интерфейс / Абстракция

/// <summary>
/// This Class Assumes the type T has a property called ID. MUST be 
/// used with IDbEquatable
/// </summary>
/// <typeparam name="T">Class Type</typeparam>
public abstract class DbTableEquatable<T> : IEquatable<T> where T : class
{
    public bool Equals(T other)
    {
        //Check whether the compared object is null.  
        if (Object.ReferenceEquals(other, null))
        {
            return false;
        }

        //Check whether the compared object references the same data.  
        if (Object.ReferenceEquals(this, other))
        {
            return true;
        }

        return ((dynamic)other).ID == ((dynamic)this).ID;
    }
}

/// <summary>
/// Needs to be inherited from in order for Ion.Data.Linq functions to work
/// </summary>
/// <typeparam name="T">Primary Key Type</typeparam>
public interface IDbTableEquatable<T>
{
    T ID { get; set; }
}

вот таблица реализации

[Table(Name = "Crews")]
public class Crew : DbTableEquatable<IDbTableEquatable<long>>, IDbTableEquatable<long>
{
    [Column(IsPrimaryKey = true, DbType = "Bigint NOT NULL IDENTITY", AutoSync = AutoSync.OnInsert, IsDbGenerated = true)]
    public long ID { get; set; }
    [Column]
    public string Alias { get; set; }
    [Column]
    public string DefaultForeground { get; set; }
    [Column]
    public string DefaultBackground { get; set; }
    [Column]
    public string AccountEmailAddress { get; set; }
    [Column]
    public long? CrewLeaderEmployeeID { get; set; }
    [Column]
    public string Comments { get; set; }
    [Column]
    public string Password { get; set; }
    [Column]
    public string PrivateICSLink { get; set; }
    [Column]
    public string PrivateXMLLink { get; set; }
}
0 голосов
/ 09 марта 2011

Передайте контекст данных в качестве параметра ref пользовательскому методу вашего частичного объекта Product:

public partial class Product 
{
    public string GetSomethingElse(ref DataContext dbase) 
    {
         return dbase.OtherTableWhatever.Count.ToString(); // whatever
    }
}

Внутри вашего aspx.cs:

var context = new DataContext();
var product = context.Products.SingleOrDefault(x => x.id == 1);
var s = product.GetSomethingElse(ref context);
0 голосов
/ 13 января 2009

На самом деле, я согласен с casperOne. Если вам действительно нужно это, я вспомнил, что классы, которые генерирует linq-to-sql, являются частичными. Таким образом, вы можете написать частичный класс для любого класса и добавить в него расширенные функциональные возможности.

...