Var til CNUG møde igår, kommer du næste gang ?


Jeg havde fornøjselsen af at være i Ballerup igår, men det var hverken hos IBM eller KMD. Der var CNUG møde for første gang og Jakob havde forberedt et rigtig godt indlæg omkring hvad ORM er og hvordan man bruger software såsom nHibernate og LINQ 2 SQL.

Der er var en 20 stykker samlet og alle var ivrige for at deltage i debatten omkring hvad de syntes en sådan gruppe skulle kunne gøre for dem og alle os andre.

CNUG er en brugergruppe for .NET udviklere, den er stiftet og vedligeholdt af Jakob Andersen (Miracle) og Mads Kristensen (ZYB). Alle er velkomne og det er helt gratis...ja, det er helt gratis.

Flere havde haft problemmer med LINQ 2 SQL implementationen i deres applikation, mest fordi man nok skal vænne sig til den Unit of Work tankegang der ligger i brugen af ORM, men også fordi det er en lidt anden måde at håndtere sine data på end f.eks hvis man snakkede direkte med databasen. Der er arbejde i at have med ORM at gøre og noget af det Jakob lagde meget vægt på i sit oplæg var at man skal kende sin ORM. Ligsom med alt andet for du intet foræret uden at der arbejde ivolveret.

Jeg har implementeret LINQ 2 SQL i et projekt, og det køre strålende. Nis Wilson Nissen fra Knappe & Kragh i Svendborg har gjort det samme i deres produkt, og de har en masse data, men ikke noget LINQ 2 SQL ikke kan håndtere.

Du kan vælge at implementere LINQ 2 SQL med en DataContext pr. Request. Jeg er sikker på der er andre måder at gøre dette på, men her er min måde:

using System.Web;

namespace DAL
{
    /// <summary>
    /// Simple class to implement request-scoped DataContext pattern for LINQ to SQL.
    /// </summary>
    public static class DataContextHelper
    {
        #region Privates

        /// <summary>
        /// Dictionary key for the DataContext in HttpContext.Current.Items
        /// </summary>
        private const string DATACONTEXT_ITEMS_KEY = "MyDataContext";

        /// <summary>
        /// Private property to store the DataContext in the HttpContext.Current.Items
        /// </summary>
        private static MyDataContext InternalDataContext
        {
            get
            {
                return (MyDataContext)HttpContext.Current.Items[DATACONTEXT_ITEMS_KEY];
            }
            set
            {
                HttpContext.Current.Items[DATACONTEXT_ITEMS_KEY] = value;
            }
        }

        #endregion

        #region Public and Protected Properties and Methods

        /// <summary>
        /// Returns the current DataContext. If none configured yet, then creates a new one and returns it. Internal access
        /// so that only the DAL layer can access.
        /// </summary>
        /// <returns>A reference to a DataContext</returns>
        internal static MyDataContext DataContextInstance
        {
            get
            {
                // If the context is missing, create a new one
                if (InternalDataContext == null)
                {
                    InternalDataContext = new MyDataContext();
                }

                return InternalDataContext;
            }
        }

        /// <summary>
        /// Saves all changes on the current DataContext. Public scope to allow calling from upper tiers of application.
        /// </summary>
        public static void SubmitChanges()
        {
            DataContextInstance.SubmitChanges();
        }

        /// <summary>
        /// Cleanup the context (dispose the context and set it to null). Public scope allows calling from upper tiers.
        /// </summary>
        public static void CleanUp()
        {
            if (InternalDataContext != null)
            {
                InternalDataContext.Dispose();
                InternalDataContext = null;
            }
        }

        #endregion
    }
}

Istedet for at oprette en DataContext for hver gang du skal bruge den gemmer du din instans i en slags cache (HttpContext.Current.Items) og genbruger samme DataContext hver gang du laver et kald til databasen.

En meget simpel måde at vise det på er følgende:

using System.Linq;

/// <summary>
/// Summary description for UserDal
/// </summary>
public class UserDal
{
    public static void Insert(User user)
    {
        DAL.DataContextHelper.DataContextInstance.Users.InsertOnSubmit(user);
        DAL.DataContextHelper.DataContextInstance.SubmitChanges();
    }

    public static User GetById(int userId)
    {
        var userQuery = from users in DAL.DataContextHelper.DataContextInstance.Users
                        where (users.pk_user == userId)
                        select users;

        return userQuery.Single();
    }

    public static void Update(User user)
    {
        DAL.DataContextHelper.DataContextInstance.SubmitChanges();
    }
}

Her har vi en simpel klasse hvorpå der er et par metoder som skal gøre forskellige ting. Det er nemt at se sig ud af.

Hvis man ikke bruger den samme DataContext for man fejl ved selv de mest enkelte kald.

using System;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        UserDal.Insert(new User { email = "daniel", username = "daniel" });
        User daniel = UserDal.GetById(27);

        daniel.username = "daniel_hulla";

        UserDal.Update(daniel);
    }
}

Her ser du en simpel side som indsætter, henter og opdatere.

Jeg synes du skal prøve at se om det virker med og uden din hjælpe metode, så kan du selv se hvad jeg mener.

Håber i kan bruge det til noget :0)

Comments (2)
  1. jta says:

    Den funktionalitet du stiller til rådighed på dit DAL kan godt være noget misvisende for dem der skal bruge det.

    I det øjeblik du kalder din Update metode på dit UserDAL vil alle andre instanser der er hentet via din DataContext og senere ændret også blive persisteret til databasen og ikke kun den aktuelle bruger. Dette kan virke meget forvirrende hvis udvikleren der bruger datalaget ikke ved at det forholder sig sådan.

    Derudover foretrækker jeg at min context lukker automatisk når requestet slutter da det i mere kompleks kode kan være svært at vide hvornår det rigtige tidspunkt er at dispose datacontexten på(rækkefølge på kontroleksekvering, dynamisk tilføjede kontroller der bruger dit DAL osv). Faktisk har du også glemt at rydde op efter dig i dit eksempel 😉

Comments are closed.

Skip to main content