Dailycode.info

Short solution for short problems

Combining self-tracking entities context with a Generic Singleton class. (Caching and/or refreshing)

This post is because I was using a generic singleton to instantiate the context of the entity framework. This resulted in a good chaching framework. All requests were enjoying this cached framework and passing changes to each other. But then some data was changed by an external application, even some data manipulated directly on the DB. The website did not reacht to these results, unless you would recycle the applicatin pool and release the generic singleton instance. So we came up wih a solution combining the strengt of this caching principle and still react to changes outside of the context.

We have several process layer classes in which we relate several data. For example for all master data I have a class MasterDataPL.cs: this class instantiates the context of the entity framework. Since its more or less static data, we can fully use the single instance. I also have a class with production data. The difference here is in the instantiating. Since this data changes a lot, I need to get a new instance of the context before every selection of data. The data can be manipulated from outside of the program, even directly in the database. To reflect these changes immediately, we cannot cache the data.

In the master data class, I will instantiate the context only once and use this instance as long as the process lasts:

private MyProjectEntities.Entities ents;

 

public MyProjectEntities.Entities StaticEnts

{

    get

    {

        if (ents == null)

        {

            ents = new MyProjectEntities.Entities(ConnectionString.ToString());

        }

        return ents;

    }

}

 

To get static data I just use the property accessor  StaticEnts. Also insert, update and delete actions will use this StaticEnts property.  Since this data is not manipulated from outside frequently (because the data is still refreshed after a recycle of the app pool).

Get data

public List<Users> GetAllUsers()

{

    return StaticEnts. Users.OrderBy(u => u.LastName).ThenBy(u => u.FirstName).ToList();

}

 

Update data

public void SaveProject(Projects project)

{

    try

    {

        project.Modified = DateTime.Now;

        StaticEnts.Projects.ApplyChanges(project);

        StaticEnts.SaveChanges();

    }

    catch (Exception er)

    {

        StaticEnts.Refresh(RefreshMode.StoreWins, project);

        throw new ArgumentException("Save failed, please check your data!", er.InnerException);

    }

}

 

Now, for the variable data, we still use the static property accessor for all insert, update and delete. But for the selection of data, we use a new instance of the context. Resulting in 2 properties, that we can use depending on the data:

private MyProjectEntities.Entities ents;

 

public MyProjectEntities.Entities Ents

{

    get

    {

        ents = new MyProjectEntities.Entities(ConnectionString.ToString());

        return ents;

    }

}

 

public MyProjectEntities.Entities StaticEnts

{

    get

    {

        if (ents == null)

        {

            ents = new MyProjectEntities.Entities(ConnectionString.ToString());

        }

        return ents;

    }

}

 

So to get data, it simply looks like this:

public ProjectDomains GetDomain(int domainID)

{

    return Ents.ProjectDomains.Where(pd => pd.DomainID == domainID).FirstOrDefault();

}

 

This will get the latest data from the database.  This way we minimalize the delays for getting data from and sending data to the database.

The caching now happens using the generic singleton pattern:

GenericSingleton<MYProjectsPL.ProjectsPL>.GetInstance().GetAllProjects(userID);


Create a custom event handler for an ASP.net user control with custom event arguments.

Just a quick tutorial on how to pass events from a user controls to the page.

Imagine you have a user control that has some drop down lists filled. When the dropdown list selection changes, you want to pass this event to the page that is implementing the user control.

First lets create our own general event handler using our own event arguments (This class can be in a general class, so you can reuse it):

/// <summary>

/// Summary description for Project Drop Down

/// </summary>

public class PDDCommandEventArgs

{

    private string _id;

    public string ID

    {

        get { return _id; }

    }

 

    private string _description;

    public string Description

    {

        get { return _description; }

    }

    public PDDCommandEventArgs(string guid, string description)

    {

        _id = guid;

        _description = description;

    }

}

 

public delegate void PDDCommandEventHandler(object sender, PDDCommandEventArgs e);

 

Next , we declare the event handler on our user control:

public event PDDCommandEventHandler ValueChanged;

 

Then we fire the event when the dropdown is selected on the user control:

private void OnValueChanged(object sender, PDDCommandEventArgs e)

{

    if (ValueChanged != null) ValueChanged(this, e);

}

 

protected void drpSteps_SelectedIndexChanged(object sender, EventArgs e)

{

    OnValueChanged(this, new PDDCommandEventArgs(this.drpSteps.SelectedValue, this.drpSteps.SelectedItem.Text));

}

 

Once a page that uses this control has declared the event handler, it will be fired when the selection changes:

projectDropDown1.StepChanged += new ZinqProjectsWeb.Controls.PDDCommandEventHandler(projectDropDown1_StepChanged);

void projectDropDown1_StepChanged(object sender, Controls.PDDCommandEventArgs e)

{

    taskDetailsControl.FillDefaults(int.Parse(e.ID));

}

 


A very easy and quick way to loop over Entity properties using reflection.

A very easy and quick way to loop over Entity properties using reflection. In the loop I loop over the properties and add some properties to a list. 

 

using System.Reflection;

 

var properties = typeof(MyEntity).GetProperties(BindingFlags.Public | BindingFlags.Instance);

foreach (var property in properties)

{

    var type = property.PropertyType;

    if (type == typeof(String) || type == typeof(Int16) || type == typeof(Int32) || type == typeof(Decimal?))

    {

        drpFields.Items.Add(new ListItem(property.Name, property.Name));

    }

}



The EntitySet name ‘ ' could not be found.

Frustrating error, easy to fix, hard to find!

Server Error in '/' Application.


The EntitySet name 'Entities.GP_MES_Complaint' could not be found. 

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.InvalidOperationException: The EntitySet name 'Entities.GP_MES_Complaint' could not be found.

Source Error: 

 

Line 104:        public ObjectSet<GP_MES_Complaint> GP_MES_Complaint

Line 105:        {

Line 106:            get { return _gP_MES_Complaint  ?? (_gP_MES_Complaint = CreateObjectSet<GP_MES_Complaint>("GP_MES_Complaint")); }

Line 107:        }

Line 108:        private ObjectSet<GP_MES_Complaint> _gP_MES_Complaint;


In my case I made a mistake in the entity connection string. Because I’m working with multiple edmx models on the same database, I just copied the connection string. But then the entity framework has troubles since it adds mapping stuff to the default connection string:

   <add key="GMConnectionString" value="metadata=res://*/GMModel.csdl|res://*/GMModel.ssdl|res://*/GMModel.msl;provider=System.Data.SqlClient;provider connection string='Data Source…

    <add key="GMSysConnectionString" value="metadata=res://*/SYS.GMSystemModel.csdl|res://*/SYS.GMSystemModel.ssdl|res://*/SYS.GMSystemModel.msl;provider=System.Data.SqlClient;provider connection string='Data Source…

 

 My mistake was I used the connection string of an existing edmx model, but I had to change it to map the edmx model. Haaa. Frustrating!

 

 <add key="GMViewsConnectionString" value="metadata=res://*/VIEWS.GMViewsModel.csdl|res://*/VIEWS.GMViewsModel.ssdl|res://*/VIEWS.GMViewsModel.msl;provider=System.Data.SqlClient;provider connection string='Data Source…


Devexpress aspxgrid: Show dynamic images in a column (Part 2)

As I was using the grid in part 1, I noticed that the icon disappeared when I used sorting, or when I changed column places at runtime. This was because the HTML row created event was not called when these events happens, but a databind was done. At the moment I didn’t found a good solution, but then my colleague found a better way to databind image at runtime.

No more HTMLRowCreated event!

I improved the MyImageTemplate class that derives from the ITemplate.  There I take the databound object and directly check the property and select the image url. I added the public string property Function that will choose which dataitem to check and selects the correct function to check. You could make a ITemplate class for every column, or you could do it like this:

class MyImageTemplate : ITemplate

{

    public string ID { get; set; }

 

    public string Function { get; set; }

 

    public void InstantiateIn(Control container)

    {

        ASPxImage img = new ASPxImage();

        GridViewDataItemTemplateContainer gridContainer = (GridViewDataItemTemplateContainer)container;

        GridViewDataItemTemplateContainer ri = (GridViewDataItemTemplateContainer)gridContainer.NamingContainer;

        object dataValue =null ;

        try

        {

            dataValue = DataBinder.Eval(gridContainer.DataItem, Function);

        }

        catch { }

        img.ID = ID;

        img.ImageUrl = GetImageUrl(dataValue);

        container.Controls.Add(img);

    }

 

    private string GetImageUrl(object dataValue)

    {

        switch (Function.ToLower())

        {

            case "orderposshipmentready":

                return CheckOrderPosShipMentReady(dataValue);

            case "rushorder":

                return CheckRushOrder(dataValue);

            case "ordericon01":

                return CheckSpecial(dataValue);

            case "ordericon02":

                return CheckSize(dataValue);

            case "ordericon03":

                return CheckCoatingPrep(dataValue);

            default: return "";

        }

    }

 

    private string CheckOrderPosShipMentReady(object dataValue)

    {

        bool bShipmentReady = Convert.ToBoolean(dataValue);

 

        if (bShipmentReady)

        {

            return "~/Images/OK.gif";

        }

        else

        {

            return "~/Images/NOK.gif";

        }

    }

 

    private string CheckRushOrder(object dataValue)

    {

        bool check = false;

        try

        {

            if (dataValue.ToString() == "R")

            {

                check = true;

            }

        }

        catch { }

        if (check)

        {

            return "~/Images/rush.gif";

        }

        return "";

    }

 

 

 

    private string CheckSpecial(object dataValue)

    {

 

        bool check = false;

        try

        {

 

            if (dataValue.ToString() == "O0")

            {

                check = true;

            }

        }

        catch { }

        if (check)

        {

            return "~/Images/special.gif";

        }

        return "";

    }

 

    private string CheckSize(object dataValue)

    {

        bool check = false;

        try

        {

            if (dataValue.ToString() == "O1")

            {

                check = true;

            }

        }

        catch { }

        if (check)

        {

            return "~/Images/dikte.gif";

        }

        return "";

    }

 

    private string CheckCoatingPrep(object dataValue)

    {

        bool check = false;

        try

        {

            if (dataValue.ToString() == "O2")

            {

                check = true;

            }

        }

        catch { }

        if (check)

        {

            return "~/Images/paint.gif";

        }

        return "";

    }

}

 

The hardest part was to get the databound item from the row. Using the DataBinder.Eval function it had to work. Then it was just the case of getting the dataitem container that was bound. This code did the trick:

GridViewDataItemTemplateContainer gridContainer = (GridViewDataItemTemplateContainer)container;

GridViewDataItemTemplateContainer ri = (GridViewDataItemTemplateContainer)gridContainer.NamingContainer;

object dataValue =null ;

try

{

dataValue = DataBinder.Eval(gridContainer.DataItem, Function);

}

catch { }

 

Now to add this column at runtime, I simply create an instance of the MyImageTemplate and provide the 2 properties. Then the data binding does the rest:

GridViewDataColumn col1 = new GridViewDataColumn();

col1.Caption = ".";

col1.FieldName = property.Name;

col1.Width = Unit.Pixel(int.Parse(showColumns[count]));

col1.VisibleIndex = 0;

col1.DataItemTemplate = new MyImageTemplate() { ID = "ASPxImage1", Function="OrderPosShipmentReady" };

grdOrderLocations.Columns.Add(col1);

 

Now sorting and all other functions work! Be sure that the grid databind is called in the page load and not the page init.

 


Addressing tables that are not in the EDMX model.

When you are working with the entity framework, it’s no problem to use non referenced tables that belong to the same database. By using the ExecuteStoredQuery function, you can provide an SQL script. Keep in mind that the returned data needs to be mapped to your entity. Here a small example:

public Clients GetClientForPlant(string plantID)

{

    return Ents.ExecuteStoreQuery< Clients>("select * from Clients c inner join Plants p on c.Client = p.Client and p.Plant = @p0", new SqlParameter() { ParameterName = "p0", Value = plantID }).First();

}


Why use a Response.End after a Response.Redirect or why use a Response.Redirect(url,false)?

 

Just a quick example to show why it could come in handy:

protected void btnBack_Click(object sender, EventArgs e)

{

    if (Session["LocationControlUrl"]!=null)

    {

        Response.Redirect(Session["LocationControlUrl"].ToString(), false);

        Session.Remove("LocationControlUrl");

        Response.End();

    }

}

 

So you can remove a session value after the redirect.