Click here to Skip to main content
Click here to Skip to main content

LINQ to SQL: All common operations (Insert, Update, Delete, Get) in one base class

, 31 May 2008
Rate this:
Please Sign up or sign in to vote.
A base class to perform all common LINQ to SQL operations.

Introduction

I have been playing with LINQ to SQL for a bit. It is great and easy to use along with the designer that ships with VS.NET 2008. I wanted to create a Facade layer that integrates with LINQ to SQL classes. The old school way is to create a public class (Manager) and this class calls your database mappers to get/set the required info. Now, LINQ to SQL replaces those mapper classes, and the way to do your operations is to open the DataContext and start defining queries to perform such operations.

So, I grouped those queries and operations into another separate layer called Processes/Operations layer in which the facade will end up calling. By doing that, the Facade remains as is and the Processes/Operations layer replaces the mappers layer while it encapsulates the whole logic and complexity for the DB operations.

Having said that, I created a base class which encapsulates the most common logic for database operations in the Processes/Operations layer instead of repeating the same code over and over for each class.

Note: This article is intended for people familiar with LINQ and LINQ to SQL.

Using the code

Class definition

Shown below is the definition of the class:

internal class DataBaseProcessBase<T, DC> where T : 
               class, new() where DC : DataContext, new()

As you can notice, this is a generic class taking two types: the first one is your entity type, while the second is your DataContext. Moving forward, here are the operations listed in that class:

  1. Add
  2. Get
  3. Update
  4. Delete

You just create a class that inherits from this one, as follows:

internal class MyProcess : DataBaseProcessBase<MyEntity,MyDataContext>

The Add operation

/// <span class="code-SummaryComment"><summary></span>
/// Adds a new record to the DB
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><param name="entity">Current Object</param></span>
/// <span class="code-SummaryComment"><param name="IdPropertyName">Name of the property</span>
///          containing identity Column or the ID returned by 
/// the DB<span class="code-SummaryComment"></param></span>
/// <span class="code-SummaryComment"><returns><see cref="System.Object"/> </returns></span>
protected virtual object Add(T entity, string IdPropertyName)
{
    using (DC db = new DC())
    {
        db.GetTable<T>().InsertOnSubmit(entity);
        db.SubmitChanges();
    }
    return entity.GetType().GetProperty(IdPropertyName).GetValue(entity, null);
}

The add operation is pretty easy and straightforward. It just inserts the entity into the database and returns the ID of the new record. Note, the second parameter is the ID property name as I'm using Reflection to get the value of the ID property for the inserted entity.

How to use

base.Add(MyEntity, "ID");

Note: the name of the property is case sensitive.

The Get operation

/// <span class="code-SummaryComment"><summary></span>
/// Select From DB on the defined query
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><param name="options"><see
/// cref="System.Data.Linq.DataLoadOptions"/></param></span>
/// <span class="code-SummaryComment"><param name="query">Select Query</param></span>
/// <span class="code-SummaryComment"><param name="from">for pagination Purposes, starting Index</param></span>
/// <span class="code-SummaryComment"><param name="to">for pagination Purposes, End Index</param></span>
/// <span class="code-SummaryComment"><returns>collection of the current type,</span>
/// <span class="code-SummaryComment"><see cref="System.System.Collections.Generic.IList<T>"/></returns></span>
/// <span class="code-SummaryComment"><remarks>if "to" parameter was passed as 0,</span>
/// it will be defaulted to 100, you can replace it by
/// a valued defined in the config, and another point
/// of interest, if from > to, from will be
/// reseted to 0.
/// 
/// if there is no query defined, all results will be
/// returned, and also if there is no load data options
/// defined, the results will contain only the entity specified
/// with no nested data (objects) within that entity.
/// <span class="code-SummaryComment"></remarks></span>
protected virtual IList<T> Get(DataLoadOptions options, 
          Expression<Func<T, bool>> query, int from, int to)
{
    IList<T> list = null;
    if (to == 0)
        to = 100;
    if (from > to)
        from = 0;
    using (DC db = new DC())
    {
        if (null != options)
            db.LoadOptions = options;
        if (null == query)
            list = db.GetTable<T>().Skip(from).Take(to - from).ToList();
        else
            list = 
              db.GetTable<T>().Where(query).Skip(from).Take(to - from).ToList();
    }
    return list;
}

The get method consists of four parameters:

  • DataLoadOptions: if defined, it would be assigned to the database.
  • Expression<Func<T,bool>> query: this is the query or Lambda expression in which the results will be returned upon.
  • int from: starting index, for pagination purpose.
  • int to: ending index, also for pagination purpose.

How to use

DataLoadOptions options = new DataLoadOptions();
//Load my object along with nested object with it,
//as an example MyObject = Customer, MyNestObject=Orders
options.LoadWith<MyObject>(m => m.MyNestedEntity);

base.Get(options,m => m.CategoryID == 1,0,100);

Suppose that you have a class called MyObject and this class has two properties, CategoryId and MyNestedObject. Here is the scenario, we want to get 100 results of MyObject where its CategoryID equals to 1 along with its nested object.

There are two overloads for this method, as shown:

/// <span class="code-SummaryComment"><summary></span>
/// Select From DB on the defined query
/// <span class="code-SummaryComment"></summary>        </span>
/// <span class="code-SummaryComment"><param name="query">Select Query</param></span>
/// <span class="code-SummaryComment"><param name="from">for pagination Purposes, starting Index</param></span>
/// <span class="code-SummaryComment"><param name="to">for pagination Purposes, End Index</param></span>
/// <span class="code-SummaryComment"><returns>collection of the current type, </span>
///<span class="code-SummaryComment"><see cref="System.System.Collections.Generic.IList<T>"/></returns></span>
/// <span class="code-SummaryComment"><remarks>if "to" parameter was passed as 0, it will be defaulted to 100, </span>
///you can replace it by a valued defined in the config, and another point of 
/// interest, if from > to, from will be reseted to 0<span class="code-SummaryComment"></remarks></span>
protected virtual IList<T> Get(Expression<Func<T, bool>> query, int from, int to)
{
    return Get(null, query, from, to);
}
/// <span class="code-SummaryComment"><summary></span>
/// Select All From DB
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><param name="from">for pagination Purposes, starting Index</param></span>
/// <span class="code-SummaryComment"><param name="to">for pagination Purposes, End Index</param></span>
/// <span class="code-SummaryComment"><returns>collection of the current type,</span>
///<span class="code-SummaryComment"><see cref="System.System.Collections.Generic.IList<T>"/></returns></span>
/// <span class="code-SummaryComment"><remarks>if "to" parameter was passed as 0, it will be defaulted to 100, </span>
///you can replace it by a valued defined in the config, and another point of 
/// interest, if from > to, from will be reseted to 0<span class="code-SummaryComment"></remarks></span>
protected virtual IList<T> Get(int from, int to)
{
    return Get(null, null, from, to);
}

Points of interest

Each parameter defined in the get method can be null. Starting from the first one, if DataLoadOptions is null, it won't be assigned to the database context. If the query is null, then all results will be returned depending on the pagination indexes specified. And, last but not least, if the 'to' parameter is 0, then it will be defaulted to 100 (you can change this by a config value) and if the 'from' is greater than the 'to' parameter, it will be defaulted to 0 (also, you can change it if you don't like this behaviour).

Those methods are a great way when you do your search; based on conditions, you build up your query, and then you call one of those methods.

Remember, those methods will get any data based on the provided query. If you want to filter such get methods on the client code, you just create your methods in the facade and the process class, as follows:

public static class FacadeExample
{
  public static MyEntity GetMyEntityByID(int id)
      {
    return (new MyProcess()).GetByID(id);
   }
 }

Now, in the MyProcess class (the one defined at the top of this article), add the same method but add the query logic to get by ID, somehow like this:

public MyEntity GetByID(int id)
{
  return base.Get(m => m.ID == id,0,1)[0];
}

In the facade class, notice that we are instantiating a new instance of the MyProcess class (new MyProcess()), so each time this method is called, a new instance will be created. This is not a good practice, but I added it there for quick referencing the class as it's not related to this article subject. Consequently, you should think of a singleton or a factory class to get your process instances instead of creating a new instance each time a method is called.

Note: The code listed above will throw an IndexOutOfRangeException if the results count is zero, so you should always do null and count checking before returning results.

The Update operation

/// <span class="code-SummaryComment"><summary></span>
/// Updates Entity
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><param name="entity">Entity which hold the updated information</param></span>
/// <span class="code-SummaryComment"><param name="query">query to get the same</span>
/// entity from db and perform the update operation<span class="code-SummaryComment"></param></span>
/// <span class="code-SummaryComment"><remarks>this method will do dynamic property mapping between the passed entity</span>
/// and the entity retrieved from DB upon the query defined,
/// ONLY ValueTypes and strings are
/// mapped between both entities, NO nested objects will be mapped, you have to do
/// the objects mapping nested in your entity before calling this method<span class="code-SummaryComment"></remarks></span>
protected virtual void Update(T entity, Expression<Func<T, bool>> query)
{
   using (DC db = new DC())
   {
    object propertyValue = null;
        T entityFromDB = db.GetTable<T>().Where(query).SingleOrDefault();
          if (null == entityFromDB)
             throw new NullReferenceException("Query Supplied to " + 
                   "Get entity from DB is invalid, NULL value returned");
        PropertyInfo[] properties = entityFromDB.GetType().GetProperties();
        foreach (PropertyInfo property in properties)
        {
           propertyValue = null;
                if (null != property.GetSetMethod())
                {
                  PropertyInfo entityProperty = 
                        entity.GetType().GetProperty(property.Name);
                    if (entityProperty.PropertyType.BaseType == 
                        Type.GetType("System.ValueType")|| 
                        entityProperty.PropertyType == 
                        Type.GetType("System.String"))

                      propertyValue = 
                       entity.GetType().GetProperty(property.Name).GetValue(entity, null);
                    if (null != propertyValue)
                        property.SetValue(entityFromDB, propertyValue, null);
                }
            }
            db.SubmitChanges();
        }
    }

The update operation is a bit tricky because the properties mapping between the passed entity and the entity from the database is done dynamically, so any nested object will not be mapped. The only property mapping would be against value types and string values. If you want to use this method as is, then you should do the logic of mapping objects in your entity, then use this method as a final step to map the other value types and string properties you have.

How to use

base.Update(MyEntity,e => e.ID == MyEntity.ID);

How it works

Depending on the query expression, this method will get the entity from the database, then do a dynamic property mapping between the passed entity and the retrieved one, and then submit the changes. So, in the above example, I am updating the database entity where the ID = the passed entity ID.

Points of interest

The reason why we are getting the entity from the database and doing the mapping is, as you can notice, we are using the Facade to get our entities. So, once the database context is closed, then we cant submit the changes using the entity passed to this method. As you will hit an Object Disposed exception, the other way around is to get the entity from the database, do the mapping, and then submit the changes.

Updated

I have been thinking of the mapping between the properties in the update method and wasn't satisfied with the design, so I redesigned the whole mapping thing and plugged in a mapping provider for each type supported, where you can also create your own providers and plug them into play.

First, I created an interface as follows:

/// <span class="code-SummaryComment"><summary></span>
/// Common interface for all Property Mapping Providers
/// <span class="code-SummaryComment"></summary></span>
public interface IPropertyMappingProvider
{
    /// <span class="code-SummaryComment"><summary></span>
    /// Responsible for mapping the two properties
    /// <span class="code-SummaryComment"></summary></span>
    /// <span class="code-SummaryComment"><param name="entity">Entity received from</span>
    /// the client code, <span class="code-SummaryComment"><see cref="System.Object"/></param></span>
    /// <span class="code-SummaryComment"><param name="LINQEntity">Entity retrieved from DB</param></span>
    /// <span class="code-SummaryComment"><param name="LINQProperty"></span>
    /// <span class="code-SummaryComment"><see cref="System.Reflection.PropertyInfo"/> from LINQ entity</span>
    /// retrieved from DB to be mapped<span class="code-SummaryComment"></param></span>
    void MapProperties(object entity, object LINQEntity, PropertyInfo LINQProperty);
}

And, a base property mapper class that implements the previous interface:

internal class PropertyMappingProviderBase : IPropertyMappingProvider
{
    #region IPropertyMappingProvider Members
    /// <span class="code-SummaryComment"><summary></span>
    /// Encapsulates the common functionality of mapping two 
    ///properties using <span class="code-SummaryComment"><see cref="System.Reflection"/></span>
    /// <span class="code-SummaryComment"></summary></span>
    /// <span class="code-SummaryComment"><param name="entity">Entity received from the client code, </span>
    ///<span class="code-SummaryComment"><see cref="System.Object"/></param></span>
    /// <span class="code-SummaryComment"><param name="LINQEntity">Entity retrieved from DB</param></span>
    /// <span class="code-SummaryComment"><param name="LINQProperty"></span>
    /// <span class="code-SummaryComment"><see cref="System.Reflection.PropertyInfo"/> </span>
    ///from LINQ entity
    /// retrieved from DB to be mapped<span class="code-SummaryComment"></param></span>
    /// <span class="code-SummaryComment"><remarks>If you want to create a new Provider, just inherit from this class</span>
    /// and have MappingPropertyTypeNameAttribute set to the type you are providing 
    ///the mapping
    /// against<span class="code-SummaryComment"></remarks></span>
    public virtual void MapProperties(object entity, 
           object LINQEntity, PropertyInfo LINQProperty)
    {
        object propertyValue = null;
        //Get Property from entity
        PropertyInfo entityProperty = entity.GetType().
    GetProperty(LINQProperty.Name);
        //Get Value from the property
        if (null != entityProperty)
            propertyValue = entityProperty.GetValue(entity, null);
        //Set LinqEntity to the value retrieved from the entity
        if (null != propertyValue)
            LINQProperty.SetValue(LINQEntity, propertyValue, null);
    }
    #endregion
   
}

So, as you can see, the base class implements the IPropertyMappingProvider, which has only one method, MapProperties. The MapProperties method accepts three parameters: the first one is your entity received from the client code, the next one is the entity retrieved from the database, and the last one is the property which the mapping will be held against.

Now, here is the fun part of creating providers. But, before pasting the code for each provider, the provider for each type should be initialized dynamically. No switch statements to initialize them, and no hardcoded values in the class responsible for initializing the correct providers. So, what's the best way to do this????

I found that creating a custom attribute and decorating our provider classes with it is the way. Here is the definition of it:

/// <span class="code-SummaryComment"><summary></span>
/// Attribute specified on a <span class="code-SummaryComment"><see cref="IPropertyMappingProvider"/></span>
/// indicating the type of property that it maps
/// <span class="code-SummaryComment"></summary></span>
[AttributeUsage(AttributeTargets.Class)]
public class MappingPropertyTypeNameAttribute : System.Attribute
{
    private string _propertyTypeName;
    public MappingPropertyTypeNameAttribute(string propertyTypeName)
    {
        _propertyTypeName = propertyTypeName;
    }
    public string PropertyTypeName
    {
        get
        {
            return _propertyTypeName;
        }
        
    }

Simply, this attribute is assigned to each provider class (except the base), which will hold the fully qualified name of the type that it will process (e.g.: System.String). So now, I can list the two providers I have created: one for string values and the other one for value types:

String mapping provider:

/// <span class="code-SummaryComment"><summary></span>
/// Responsible for mapping String Values between both properties
/// <span class="code-SummaryComment"></summary></span>
[MappingPropertyTypeName("System.String")]
internal class StringPropertyMappingProvider : PropertyMappingProviderBase
{
    /// <span class="code-SummaryComment"><summary></span>
    /// Map String Values
    /// <span class="code-SummaryComment"></summary></span>
    /// <span class="code-SummaryComment"><param name="entity">Entity received from the client code,</span>
    /// <span class="code-SummaryComment"><see cref="System.Object"/></param></span>
    /// <span class="code-SummaryComment"><param name="LINQEntity">Entity retrieved from DB</param></span>
    /// <span class="code-SummaryComment"><param name="LINQProperty"></span>
    /// <span class="code-SummaryComment"><see cref="System.Reflection.PropertyInfo"/> from LINQ entity</span>
    /// retrieved from DB to be mapped<span class="code-SummaryComment"></param></span>
    public override void MapProperties(object entity, 
                    object LINQEntity, PropertyInfo LINQProperty)
    {
        base.MapProperties(entity, LINQEntity, LINQProperty);
    }
}

Value types mapping provider:

/// <span class="code-SummaryComment"><summary></span>
/// Responsible for mapping Value types between both properties
/// <span class="code-SummaryComment"></summary></span>
[MappingPropertyTypeName("System.ValueType")]
internal class ValueTypePropertyMappingProvider : PropertyMappingProviderBase
{
    /// <span class="code-SummaryComment"><summary></span>
    /// Map Value types
    /// <span class="code-SummaryComment"></summary></span>
    /// <span class="code-SummaryComment"><param name="entity">Entity received from the</span>
    /// client code, <span class="code-SummaryComment"><see cref="System.Object"/></param></span>
    /// <span class="code-SummaryComment"><param name="LINQEntity">Entity retrieved from DB</param></span>
    /// <span class="code-SummaryComment"><param name="LINQProperty"></span>
    /// <span class="code-SummaryComment"><see cref="System.Reflection.PropertyInfo"/> from LINQ entity</span>
    /// retrieved from DB to be mapped<span class="code-SummaryComment"></param></span>
    public override void MapProperties(object entity, 
                    object LINQEntity, PropertyInfo LINQProperty)
    {
        base.MapProperties(entity, LINQEntity, LINQProperty);
    }
}

Notice the MappingPropertyTypeName which is set exactly to the type name. Nothing special in both classes except calling the base method. But, it's a good practice to create a provider for each type in case you want to do more manipulation, or if you want to change the behaviour of one of them without affecting others.

Now, everything is set, the only thing missing is our facade class to initiate the right provider dynamically. So, here is the definition of that class:

/// <span class="code-SummaryComment"><summary></span>
/// Entry Point for the Client code to map the properties
/// <span class="code-SummaryComment"></summary></span>
public static class MappingProvider
{
    /// <span class="code-SummaryComment"><summary></span>
    /// Map Properties between two objects
    /// <span class="code-SummaryComment"></summary></span>
    /// <span class="code-SummaryComment"><param name="entity">Entity received from the client code, </span>
    ///<span class="code-SummaryComment"><see cref="System.Object"/></param></span>
    /// <span class="code-SummaryComment"><param name="LINQEntity">Entity retrieved from DB</param></span>
    /// <span class="code-SummaryComment"><param name="LINQProperty"></span>
    /// <span class="code-SummaryComment"><see cref="System.Reflection.PropertyInfo"/> </span>
    ///from LINQ entity
    /// retrieved from DB to be mapped<span class="code-SummaryComment"></param></span>
    /// <span class="code-SummaryComment"><remarks>This class will get the provider dynamically and will map </span>
    ///the properties
    /// using that provider, so if you want
    /// to implement your own provider, you dont
    /// have to modify anything in the code<span class="code-SummaryComment"></remarks></span>
    public static void MapProperties(object entity, 
           object LINQEntity, PropertyInfo LINQProperty)
    {
        IPropertyMappingProvider provider = null;
        //Get All Types in the current assembly which have 
        //MappingPropertyTypeNameAttribute defined
        Type[] currentProviders = Assembly.GetExecutingAssembly().GetTypes().Where(
          t => t.GetCustomAttributes(typeof(MappingPropertyTypeNameAttribute),
          false).ToArray().Length > 0).ToArray();
        if (null != currentProviders && currentProviders.Length > 0)
        {
            //Get the provider type,first try to get from its type
            //the mechanism used is to get the MappingPropertyTypeNameAttribute 
            //and compare the string defined there with the LINQProperty type
            Type providerType = currentProviders.Where(p =>
              (p.GetCustomAttributes(typeof(MappingPropertyTypeNameAttribute), 
               false).ToArray()[0] as MappingPropertyTypeNameAttribute).PropertyTypeName == 
               LINQProperty.PropertyType.ToString()).SingleOrDefault();
            //if no provider found,Try to get it from comparing LINQproperty 
            //base type with MappingPropertyTypeNameAttribute
            if(null == providerType)
              providerType = currentProviders.Where(p =>
              (p.GetCustomAttributes(typeof(MappingPropertyTypeNameAttribute), 
               false).ToArray()[0] as MappingPropertyTypeNameAttribute).PropertyTypeName == 
               LINQProperty.PropertyType.BaseType.ToString()).SingleOrDefault();
            
            if (null != providerType)
            {
                //Call the provider factory to get our instance
                provider = ProviderFactory.CreatePropertyMappingProvider(providerType);
                //Map Properties
                provider.MapProperties(entity, LINQEntity, LINQProperty);
            }
        }
    }
}

To be honest, this class was great fun to write, because it does everything dynamically using Reflection. First, it gets all the types defined in the assembly where they have our MappingPropertyTypeNameAttribute defined, meaning, it will get all our mapping providers. If it finds any, it proceeds with trying to get the right provider by comparing the passed property type with the attribute value defined on each of our provider classes, using a string comparison. If not found, then it will try and compare the base type of the property with our attribute's value (reason for that is, all value types (e.g.: Int32) have their type set to System.Int32 and their base type to value type; plus it's a good thing to expand the possibilities of comparison).

So, after finding our provider type, we need to initialize it. I created a factory class to do that job for us, as follows:

/// <span class="code-SummaryComment"><summary></span>
/// Responsible of instantiating each provider
/// and cahing it into a Dictionary
/// <span class="code-SummaryComment"></summary></span>
internal static class ProviderFactory
{
    //Static providers cache
    static IDictionary<string, IPropertyMappingProvider> providers = 
           new Dictionary<string, IPropertyMappingProvider>();

    public static IPropertyMappingProvider 
           CreatePropertyMappingProvider(Type providerType)             
    {
        IPropertyMappingProvider provider = null;
        
        //Check if the provider already exists in the cahce
        if (providers.ContainsKey(providerType.ToString()))
            provider = providers[providerType.ToString()] 
            as IPropertyMappingProvider;
        else
        {
            //Instaniate a new provider and add it to the cache
            provider=  AppDomain.CurrentDomain.CreateInstanceAndUnwrap(
                       Assembly.GetExecutingAssembly().ToString(), 
                       providerType.ToString()) as IPropertyMappingProvider;

            providers.Add(provider.GetType().ToString(), 
            provider as IPropertyMappingProvider);
         }
         return provider;
    }
}

Nothing special there, except initializing the provider and inserting it into a custom Dictionary for caching purposes, as there is no need to keep creating the provider over and over, just a singleton will do.

And finally, it calls the MapProperties method from the corresponding provider, so our Updatemethod in the base class will look like this after the modification:

protected virtual void Update(T entity, Expression<Func<T, bool>> query)
{
    using (DC db = new DC())
    {
        T entityFromDB = db.GetTable<T>().Where(query).SingleOrDefault();
        if (null == entityFromDB)
            throw new NullReferenceException("Query Supplied to Get" + 
                  " entity from DB is invalid, NULL value returned");
        PropertyInfo[] properties = entityFromDB.GetType().GetProperties();
        foreach (PropertyInfo property in properties)
        {
            if (null != property.GetSetMethod())
            {
               //Just one Line Of Code to Do the mapping
                MappingProvider.MapProperties(entity, entityFromDB, property);
            }
        }
        db.SubmitChanges();
    }
}

Last, about the update operation, the old DatabaseProcessBase class is still available in the downloads, and the new design for all the providers and the modification for the class is added as well.

The Delete operation

/// <span class="code-SummaryComment"><summary></span>
/// Deletes the entity upon the defined query
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><param name="query">Delete Query</param></span>
protected virtual void Delete(Expression<Func<T, bool>> query)
{
    using (DC db = new DC())
    {
        db.GetTable<T>().DeleteOnSubmit(
           db.GetTable<T>().Where(query).Single());
        db.SubmitChanges();
    }
}

The delete operation only takes one parameter, which is the query to perform to get the entity which is going to be deleted. You can extend this method to delete all, if no query was defined.

How to use

base.Delete(e => e.ID == 1);

Conclusion

Hope you all benefitted from this class. Thank you all for reading.

History

  • 9 May 2008 - Initial version of this article.
  • 31 May 2008 - Updated to include mapping providers to map properties between objects.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Yazeed Hamdan
Architect
Jordan Jordan
MCAD.NET, MCPD.NET

Comments and Discussions

 
Question"base" not recognized PinmemberJalle27-Aug-12 16:18 
AnswerRe: "base" not recognized PinmemberYazeed Hamdan25-Sep-12 12:15 
GeneralVery Nice PinmemberMember 439692028-Jan-11 4:49 
QuestionHow to call the "DataBaseProcessBase" class? Pinmemberrajkumard21-Jun-10 21:29 
GeneralColumnAttribute.IsPrimaryKey Pinmemberverger2-Feb-10 14:09 
GeneralIt helped me a lot! PinmemberTejaswini Prashant J10-May-09 22:54 
GeneralRe: It helped me a lot! PinmemberYazeed Hamdan28-May-09 23:40 
GeneralInteresting, but I would not recommend this... [modified] Pinmembermookies22-Nov-08 7:13 
First:
yes we should cache the properties..
 
Then, you implements the data layer with a factory TO your models object, AIE AIE..
 
So , you are breaking all the freedom to change easily your DAL to one or other object...
 
basically , you can not unit test this code, adpated it in N-tiers applications or a MVC architecture
 
Secondly, you should have a look to the extensions method...
for exemple Stephen Walter made some explication on his blog, I would recommend to make this has an extensions of your DataContext
 

basically I use extensions method to my datatcontext like for exemple,
 

public static TEntity Insert<Tentity>(this IDataContext dataContext, TEntity entityToInsert) where TEntity : class, new()
 public static TEntity Update<Tentity>(this IDataContext dataContext, TEntity EntityToUpdate, object id, string primaryKeyName) where TEntity : class, new();
 
/*the logic inside the function are very similar to your code*/
 
then In my DAL, or repository (depending on my architecture), i just have to call for exemple
_dataContext.Insert<forum>(forumToCreate);
 
This make your archicture more cleaner, and object are just model..And you do not need to map your entity, you will just have to use your existing datacontext, i hope implemented by an interface IDatacontext in your Business layer, or your controller to simplify unit testing and flexibility)
 
Basically for me in a good architecture : a model should be just able to save data in an entity, and add attribute for the validation,
 
If you add public method to it, you are loosing performance and clarity in your code, models should be be link to the database...
 
I hope you understand my concern..
 

Test Driven Development is the only way to get a quality works Poke tongue | ;-P
10 type of people: Developers , others
Have a good coding day
 

MOOKIES Wink | ;-)
modified on Saturday, November 22, 2008 1:22 PM

GeneralRe: Interesting, but I would not recommend this... [modified] PinmemberYazeed Hamdan26-Nov-08 1:59 
RantThe oh so.... useless =/ PinmemberArtiom Chilaru3-Jun-08 4:15 
AnswerRe: The oh so.... useless =/ PinmemberAndreas Kroll3-Jun-08 23:48 
GeneralRe: The oh so.... useless =/ PinmemberArtiom Chilaru4-Jun-08 1:01 
GeneralRe: The oh so.... useless =/ PinmemberYazeed Hamdan3-Jun-08 23:55 
GeneralRe: The oh so.... useless =/ PinmemberArtiom Chilaru4-Jun-08 1:08 
GeneralRe: The oh so.... useless =/ PinmemberYazeed Hamdan4-Jun-08 10:43 
GeneralRe: The oh so.... useless =/ PinmemberArtiom Chilaru4-Jun-08 10:47 
GeneralRe: The oh so.... useless =/ Pinmembervittore16-Jul-08 2:29 
GeneralRe: The oh so.... useless =/ PinmemberArtiom Chilaru4-Jun-08 2:00 
GeneralRe: The oh so.... useless =/ PinmemberAndreas Kroll4-Jun-08 3:41 
GeneralRe: The oh so.... useless =/ PinmemberArtiom Chilaru4-Jun-08 4:25 
GeneralRe: The oh so.... useless =/ PinmemberAndreas Kroll4-Jun-08 4:36 
GeneralRe: The oh so.... useless =/ [modified] PinmemberYazeed Hamdan4-Jun-08 20:13 
GeneralCaching PinmemberAlan Zhang2-Jun-08 17:46 
GeneralRe: Caching PinmemberYazeed Hamdan3-Jun-08 23:57 
GeneralVery Interesting Pinmembermerlin9812-Jun-08 4:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140709.1 | Last Updated 31 May 2008
Article Copyright 2008 by Yazeed Hamdan
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid