Linq To SQL Tutorial – Set inheritance modifiers with SQLMetal

I have created an base class which my entities inherit from that gives a property called IsNew which returns true if the the value of ID is 0; all of my tables use ID for the identifier.

 

public abstract class EntityBase
{
    public virtual int ID { get; set; }

    public bool IsNew
    {
        get
        {
            return ID == 0;
        }
    }
}

For this to work each of my entities need to use the override modifier for the ID property.  Using the O/R Designer it is possible to set the inheritance modifier for each property, but this is not possible using SQLMetal and I need to use SQLMetal to set the base class.

To overcome this I have a batch file that first creates my .dbml file using SQLMetal:

SQLMetal.exe /server:localhost /database:University /dbml:University.dbml /namespace:Entities /context:UniversityDataContext /pluralize

I then run a console application to find column nodes with the name of ID, and add the Modifier attribute:

EntityProcessor.exe University.dbml

The code for EntityProcessor looks like this:

 

static void Main(string[] args)
{
    try
    {
        //Ensure there is an argument for the DBML file
        if (args.Count() == 0)
        {
            throw new ApplicationException("DBML path expected.");
        }

        string dbml = args[0];

        //Load the DBML file
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(dbml);

        //Loop through the tables
        foreach (XmlNode node in xmlDoc.GetElementsByTagName("Table"))
        {
            //Loop through the nodes for the type
            foreach (XmlNode child in node.FirstChild.ChildNodes)
            {
                //Find the ID column node
                if (child.Name.Equals("Column") && child.Attributes["Name"].Value.Equals("ID"))
                {
                    //Create the modifier attribute to add to ID column
                    XmlAttribute modifierAttribute = xmlDoc.CreateAttribute("Modifier");
                    modifierAttribute.Value = "Override";
                    child.Attributes.Append(modifierAttribute);
                }
            }
        }

        //Save the updated DBML file
        xmlDoc.Save(dbml);

        Console.WriteLine("Processing complete");
    }
    catch (Exception ex)
    {
        Console.WriteLine("An error occured: {0}", ex.Message);
    }
}

Finally I use SQLMetal again to create my entities from the updated .dbml file:

SQLMetal.exe /code:University.cs /entitybase:EntityBase /namespace:Entities University.dbml

My new entities now have an ID property with an overrides modifier that looks like this:

[Column(Storage="_ID", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
public override int ID
{
    get
    {
        return this._ID;
    }
    set
    {
        if ((this._ID != value))
        {
            this.OnIDChanging(value);
            this.SendPropertyChanging();
            this._ID = value;
            this.SendPropertyChanged("ID");
            this.OnIDChanged();
        }
    }
}

I can now call IsNew on any of my entities to check if they have been inserted into the database.

Posted on by Joe in C#, Linq

12 Responses to Linq To SQL Tutorial – Set inheritance modifiers with SQLMetal

  1. Michael

    This post as well as most of the others have been extremely helpful to me. You have really been a big help. I was wondering however if there was a way to accomplish the EntityBase class without modifying the dbml file with your console application. My boss is having a problem with this.

    Thanks so much.

  2. Joe

    Hi Michael

    The console application it just to easily recreate the model after making changes to the database.

    If you don’t want to use SQLMetal you can set inheritance modifiers from the properties window for the DBML file.

    Cheers

  3. roberto T.

    I think the isnew is a cool feature and being able to set the dbml file to create entities which overrided properties from a base class is way cool. I wish you would help me …. see previous post :(

  4. Joe

    Hi Roberto

    I don’t seem to have a previous comment from you, what is the problem?

    Joe

  5. Michael

    Joe, I thought you might find this method for creating the base class helpful. I have not tried it, but I have seen this idea used in more then one place. http://www.davidturvey.com/blog/index.php/tag/linq-to-sql/

    Take care

  6. Michael

    In case your interested, I found another way to accomplish this without setting the inheritance modifiers via your console app (which is very cool by the way) or via the properties window. I changed the BaseEntity to an interface instead of an abstract class. This provided the same functionality with a little less work on my part. Less work means less opportunity to make a mistake.

    Thanks for all the articles. They have really been a big help to me.

  7. Joe

    Glad you found them helpful Michael

    Joe

  8. roberto T.

    Michael how were you able to turn the Entitybase to an interface when you have the IsNew method which seems to me, would have to exist outside of an interface.

  9. Amilkar

    I does not work for me and thow an exception when updateing:

    public virtual void Save(T entity)
    {
    if (entity.IsNew)
    {
    _context.GetTable().InsertOnSubmit(entity);
    }
    else
    {
    //The Exection throw here…
    _context.GetTable().Attach(entity, true);
    }
    _context.SubmitChanges();
    }

    This is the Exception message:

    An entity can only be attached as modified without original state if it declares a version member or does not have an update check policy.

    Can some one help me with this?

  10. Joe

    Amilkar

    Take a look at this post: http://www.joe-stevens.com/2009/07/10/linq-to-sql-with-wcf-services/

    The post example is silverlight, bit it explains why you get this issue and how you can resolve it.

    Cheers
    Joe

  11. Jo Kvalvaag

    Just love this implementation, Joe. This and the Base Repository/Business Logic wrapper articles are really golden. Thank you so much for sharing!

    I tried it out with a new project I am doing. The only thing I did not like abou it, was the messing about with the designer files in the DBML, adding the override to the ID property for each entity. Changing tool generated code is for me an absolute taboo, as you can only do that if you work alone.

    What I ended up doing instead was to declare a
    public abstract int GetID();
    in my entitybase, and then a
    public override int GetID()
    {
    return this.ID;
    }

    in each partial class of my entities.

    Then,

    public bool IsNew {
    get { return GetID() == 0; }
    }

    back in the entity class should do the trick without mocking about with generated code.

    Also, the attach method in existing records does not make much sense, does it? Why attach here (at least check if the entity is already attached first?):

    public void Save(T entity) {
    if (entity.IsNew) {
    _context.GetTable().InsertOnSubmit(entity);
    }
    else
    { _context.GetTable().Attach(entity, true);
    }
    _context.SubmitChanges();
    }

    Thanks again for the insight!

  12. Pingback: منابع یادگیری LINQ | alisite

Add a Comment