【问题标题】:Customizing Linq to Sql DataContext自定义 Linq to Sql DataContext
【发布时间】:2009-01-13 17:01:16
【问题描述】:

有没有简单的方法将属性添加到 Linq to Sql 生成的实体以引用其 DataContext? 例如:

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

并且产品实体有一个名为“Context”(product.Context)的属性,它引用了myContext,datacontext。

我知道如何自定义生成的实体。我的问题是如何自定义(我认为是 DataContext)来设置它为自己创建的每个实例的“上下文”属性。

我不确定我是否做对了。我想用更少的代码编写一个性能最好的业务封装模型。 当我四处搜索时,我发现 DataContext 对象非常轻量级,我认为这是向每个对象添加 DataContext 实例的好方法。这将减少每次我想更新或删除对象时,再次将分离的对象附加到新的数据上下文实例的需要。

如果您有任何其他解决方案,我将不胜感激。

谢谢

【问题讨论】:

标签: linq-to-sql datacontext


【解决方案1】:

有没有一种简单的方法可以将属性添加到 Linq to Sql 生成的实体以引用其 DataContext?

没有简单的方法可以做到这一点。

【讨论】:

  • 艰难之路:从头开始编写自己的 DataContext 和 DataTable(T) 类。
【解决方案2】:

这样做会破坏 LINQ-to-SQL 的部分目的。目的之一是允许您使用您拥有的对象,而不必根据数据库考虑更改您的设计。

在将 DataContext 附加到数据库时,您将代码中的表示与持久化它的方法相结合,这通常是一个糟糕的设计理念。

如果您觉得必须这样做,您总是可以从该类派生,然后在该类上实现一个接口,该接口公开 DataContext。

我建议实现该接口,因为您无法向 LINQ-to-SQL 设计器指示基类,并且您希望所有实体都具有共享实现。

【讨论】:

  • 我同意,但是我的应用程序有很多更新请求并且它不需要时间戳,所以我不能将它附加到新的 DataContext 并且必须再次使用它的键选择我的对象,合并它然后更新它。我认为其中有很多性能损失。我错了吗?
【解决方案3】:

请看这里:Determine the source DataContext for a Linq to Sql query

我或多或少地问了同样的问题。您可以从 linq to sql 查询返回的 IQueryable 获取上下文,但据我所知,不能从实体本身获取。

【讨论】:

    【解决方案4】:

    实际上,我同意 casperOne。如果你真的需要这个,我记得 linq-to-sql 生成的类是部分的。因此,您可以为任何您想要的类编写部分类,并为其添加扩展功能。

    【讨论】:

    • 当然,但问题是当使用 linq 查询时,它会创建一个类的实例,该类的扩展属性(在我的情况下为 DataContext)未初始化。
    【解决方案5】:

    将数据上下文作为 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);
    

    【讨论】:

      【解决方案6】:

      这是我为 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
      }
      

      扩展

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

      【讨论】:

        猜你喜欢
        • 2012-05-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-19
        • 2010-09-23
        • 1970-01-01
        相关资源
        最近更新 更多