Sunday, March 27, 2011

Inserting a new record pattern in SubSonic 3

I'm trying out the new SubSonic 3 preview, but I'm not sure about the patterns I should be using for the basic CRUD operations in my MVC project.

I'm trying to keep as much of my data logic in my models, so I added some static CRUD methods to each model's partial class.

For example, let's say I have a configuration table, which should only have a single record. So, my partial class may look something like this:

public partial class Configuration{
        // cut down; mocking hooks here IRL
        private static IRepository<Configuration> Table = new MyRepository<Configuration>();

        public static Configuration Retrieve()
        {
            var config = Table.GetAll().FirstOrDefault();
            if (config == null)
            {
                config = new Configuration();
                Table.Add(config);
            }
            return config;
        }

        public static void Update(Configuration target)
        {
            Table.Update(target);
        }
}

Currently, this doesn't work as the config table has an identity column for a primary key, and Add-ing a new record to the table throws the standard "Cannot insert explicit value for identity column" error. SubSonic 3 doesn't seem to generate classes that, upon new-ing them up, play nice with the rules of the database schema (i.e., no default values, no nullable primitives for values that are nullable in the database, etc).

Now, I can alter my table and pattern to get around these issues, but I'm wondering about when I cannot get around this issue--when I have to add a new record to the database and have an identity as my primary key.

I'm also wondering if this pattern is even correct or not. SubSonic gives you a number of different ways you can go about your repository business, so I'm not sure which one I should be using. I'd LIKE to use my models as MUCH as possible (otherwise why not just Linq to Sql?), so I don't want to use SubSonic's query building goodness when trying to CRUD my models.

What should I do here? Any advice on CRUD patterns for using SubSonic 3 in my MVC project would be welcome and +'d. Also welcome are links to websites that cover this subject for SubSonic 3 but that don't rank high in Google searches...


Asked Rob directly (link here). For my DB, at least, there's a showstopper bug in the generated code. Aaah, alpha software.


UPDATE

With the release of Subsonic3, can we have a little bump to reconsider this question?

From stackoverflow
  • First and foremost: the t4 templates are there for you to change as needed with SS3. That was the main idea with using T4 - I don't want to back you into my silliness :).

    To the question at hand - I think this might be a bug in our templates that refuses to stick a value into the PK field:

        ISqlQuery BuildInsertQuery(T item) {
            ITable tbl = _db.FindTable(typeof(T).Name);
            Insert query = null;
            if (tbl != null) {
                var hashed = item.ToDictionary();
                query = new Insert(_db.Provider).Into<T>(tbl); ;
                foreach (string key in hashed.Keys) {
                    IColumn col = tbl.GetColumn(key);
                    if (!col.IsPrimaryKey) {
                        query.Value(key, hashed[key]);
                    }
                }
            }
            return query;
        }
    

    In this, our check should actually be...

                    if (!col.IsPrimaryKey && !col.AutoIncrement) {
                        query.Value(key, hashed[key]);
                    }
    

    In this way, the non-identity will be inserted. But in reading your issue here, it sounds to me like you're not trying to insert into a non-identity.

    The email you sent me doesn't say anything about PKs as identity - your PK was a thing called "NAme" which is a string type and not and identity (auto-increment).

    I'm wondering about when I cannot get around this issue--when I have to add a new record to the database and have an identity as my primary key.

    This is what SubSonic assumes - that your PK is an IDENTITY column. If you ONLY have an IDENTITY column, we can't help you because this is a deadlocked table in that you can't insert any value into it, therefor you can't tick the IDENTITY column. Your only recourse at this point is to SET IDENTITY INSERT="off", which defeats the purpose.

    Hopefully this will answer your question? If I'm not getting it - can you do this for me:

    1. One sentence: what can't you do and what's the error
    2. What did you expect

    Thanks Will and I hope I'm not being thick.

    Will : Right, the example I gave you in the forums was different than this one (this, I believe, predated the forum question). In this example, it was attempting to insert the identity value, which your code fix does answer. But you're not answering the original question!
  • I seem to get the same question.

    When I insert a new new record into a table with an auto-incremented pk, the same exception is thrown. As I trace the code, I find the default value of the key of the Entity (generated from t4) is 0. Does that matter?

    Thanks.

  • Ok, so I'm not the only one hitting this. I haven't found a solution mentioned anywhere.

    Rob, the key value in my entities is also set to 0 when initialized... how can I resolve the problem?

0 comments:

Post a Comment