1

Is there anyway simple ways to add a property to Linq to Sql generated entity to reference its DataContext? For example:

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

and product entity has a property called "Context" (product.Context) that has a reference to the myContext, datacontext.

I know how to customize generated entities. My question is how to customize (i think DataContext) to set 'Context' property of each instance that it creates to itself.

I'm not sure I'm doing the right thing or not. I want to write a business encapsulation model that has best performance with less code. As i googled around I have find out that the DataContext object is very lightweight and there for I thought it would be a good way to add an instance of DataContext to each object. This will reduce the need to attach, detached objects again to a new instance of datacontext every time I want to update or delete them.

If you have any other solution I will really appreciate it.

Thanks

3
  • Why would you want to do this? Commented Jan 13, 2009 at 17:27
  • I am with Kev, why would you want to do this? To give an update method to the product object? Commented Jan 13, 2009 at 17:57
  • Yes. west-wind.com/weblog/posts/246222.aspx Commented Jan 13, 2009 at 21:16

6 Answers 6

2

Is there a simple way to add a property to Linq to Sql generated entity to reference its DataContext?

There is no simple way to achieve this.

Sign up to request clarification or add additional context in comments.

1 Comment

Hard way: Write your own DataContext and DataTable(T) classes from scratch.
1

In doing this, you defeat part of the purpose of LINQ-to-SQL. One of the purposes is to allow to you work with the objects that you have, and not have to change your design based on database considerations.

In attaching the DataContext to the database, you are coupling your representation in code with the means to persist it, which is generally a bad design idea.

If you feel you must do this though, you can always derive from the class and then implement an interface on that class which exposes the DataContext.

I recommend implementing the interface, since you can't indicate a base class to the LINQ-to-SQL designer, and you want to be able for all of your entities to have a shared implementation.

1 Comment

I agree, but my application has a lot of request for update and it doesn't required timestap, so I can not attach it to a new DataContext and have to SELECT my object with its key again, merge it and then update it. I think there is a lot of performance lost in it. Am I wrong?
1

See here: Determine the source DataContext for a Linq to Sql query

I asked more or less the same question. You can get the context from the IQueryable that a linq to sql query returns, but not from the entity itself as far as I know.

Comments

0

Actually, I agree to casperOne. If you really have to need this, I remembered that the classes that linq-to-sql generates are partial. So you can write a partial class to any class you want and add extended functionalities to it.

1 Comment

sure, but the problem is when using a linq query it creates an instance of the class that extended property of it (in my case DataContext) is not initialized.
0

Pass the data context as a ref parameter to a custom method on your partial Product object:

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

Inside your aspx.cs:

var context = new DataContext();
var product = context.Products.SingleOrDefault(x => x.id == 1);
var s = product.GetSomethingElse(ref context);

Comments

0

Here is a custom wrapper I made for System.Data.Linq. It contains a find method, so instead of your code:

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

you can do this

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

You can grab the code below and do any custom modifications you wish to set product.Context, but this is an example of modifying the DataContext.

I also made save and delete methods. You'll notice I go out a regrab the record even though it is being passed in. I do this because the record might get detached from the context and not update. If anyone would like the full code I can post the github link.

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

}

Interface/Abstraction

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

here is a table implementation

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.