Showing posts with label ADO.NET Entity Framework. Show all posts
Showing posts with label ADO.NET Entity Framework. Show all posts

Friday, March 4, 2016

Is a Repository really a good design pattern

Here are some interesting articles on the subject.

Is the Repository pattern useful with Entity Framework - lists several posts on why the repository pattern is not really that useful and doesn't add much value.

Favor query objects over repositories - I really like this idea. It adheres to a SRP, DRY, and is testable (if you mock the entity framework though it is still not easy).

Wednesday, December 2, 2015

Configure Code First migrations to use Singular Table Names

If you are using Code First Migration with Entity Framework you will probably have noticed that the table names it generates are all plural. Personally, I dislike this because all the contstraints including foreign keys are very confusing to read when they are plurarlized. Before you do an update-database for the first time be sure to override a method (OnModelCreating()) on your class (typicaly ApplicaionDbContext) that inherits from IdentityDbContext. The default class is called ApplicationDbContext.



public class ApplicationDbContext : IdentityDbContext
    {
        public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
        }

        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }

        public DbSet People{ get; set; }
      

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            // make the table names singular instead of plural
            //when code-first generates the table names

            modelBuilder.Conventions.Remove();
            base.OnModelCreating(modelBuilder);
        }


    }


Wednesday, April 18, 2012

Adding Custom Property to an Entity in Entity Framework

Let’s assume we have the following scenario.  We have a Person entity in the Entity Framework Model and it a relationship to a Pet entity. Assume the Pet entity has a property called PetName that we want to show on the Person detail, edit, grids, etc. The easiest way is to add a property to the Person entity called PetName. The trick is how to populate it and how to save any changes that users make to it. You can use this same technique (described below) regardless of whether the data you are pulling into the Person table is in your model, entity, etc.

Yes, I understand this example is not really a great example. The model really isn’t that great, but I hope you get the idea.

The first thing to know is that for any entity in your Entity Framework Model you can extend that object by creating a partial class that is in that entities same namespace and classname. Here is our new partial class.

namespace
{
public partial class Person
{
private string _PetName;
public string PetName
{
get
{
string val = sting.Empty;
if (!string.IsNullOrEmpty(_PetName)) val = _PetName;
else
{
if (this.Pet != null)
{
val = this.Pet.PetName;
}
_PetName = val;
}
return val;
}

set { _PetName = value; }
}

 

Notice that we populate the PetName property in a lazy load fashion. Meaning, we don’t go get the data until it is requested. If you use Include(“Pet”) when you get the Person object then the Pet object will be in memory already and not a separate round-trip to the database for each person that is accessed. This query would typically be in your Domain Service and might be called something like GetPersons() or GetPeople() if you renamed it.

This great for displaying information. Note that you don’t need the Set portion of the PetName property if you are just displaying the information and not editing it.

Adding Editing Functionality


To handle the editing we need to go to the Domain Service. Here you should have a UpdatePerson() and InsertPerson() methods. In each of these methods we want to do something to the Pet entity or even call a stored procedure, etc. In our case the the Pet entity is what we want to update so I’ll show you how to do that. Be sure to do the update AFTER the AttachAsModified call otherwise the Load() method call will fail because the currentPerson is not in the ObjectContext.

public void Person(Person currentPerson)
{
this.ObjectContext.People.AttachAsModified(currentPerson, this.ChangeSet.GetOriginal(currentPerson));
if (!currentPerson.PetReference.IsLoaded) currentPerson.PetReference.Load();
if (currentPerson.Pet != null)
{
currentPerson.Pet.PetName = currentPerson.PetName;
}
}

 

Limitations

This is actually pretty easy as you can see. One thing to note about adding properties in general is that you will get a runtime error if you try to use property we added in a Linq To Entities query. This means that filters and sorting by clicking on column headers on the GridView generally won’t work without some extra works that changes the property to the path it actually maps to. In this case it is possible, but in other cases such as stored procs being called, this mapping would not be possible.

Wednesday, June 15, 2011

Compiler error with VS2010 SP1 and SL 4 with WCF RIA Services and Entity Framework 4

Did you have a VS2010 project (before installing VS2010 SP1 or RIA Service Pack 1) that used Silverlight 4 and WCF RIA Services and Entity Framework 4 (EF4) and now that VS2010 Service Pack 1 is installed (or maybe some other framework) your Silverlight Project no longer compiles. Chances are if you are using RIA Services you may have created files that you want to share (called Shared Code)on the Server and the SL Client. This is done in RIA by using the .shared.cs file extension on a filename.

After I installed either VS2010 SP1 or RIA Services SP1 and then I tried to compile my project and got a compiler error similar to:

error CS0102: The type 'MyApp.Model.MyClassHere' already contains a definition for 'MyPropertyHere'

I learned that this may be a RIA Services SP1 regression bug from this forum. The beta had issues also.

It appears that this MAY be fixed now, but I’m not sure since I don’t have an issue exactly like what they had. I only have the issue if I have to shared files and one the classes (in one of the files) has a property or method that has a return type that is the other class type. If I get rid of that dependency and just return the object type instead then it compiles fine. While returning the type object, I have to cast every time I use it and that is silly and kind of a pain / ugly.

I hope that helps someone. If anyone else has this issue I’d love to know about it.

Wednesday, May 4, 2011

Why aren’t my ForeignKeys being loaded on my Custom Dynamic Data page?

This is one entry in a series of blog entries:

If you look at Part I and Part II, you may have noticed that the Product Category is a textfield when it should be a Drop Down List of the Product Categories. If this were a page that was in the DynamicData\CustomPages directory then you would not be having this problem. The reason we are having this problem is because we are calling EnableDynamicData() on our FormView which is great to get basic dynamic data functionality, but it doesn’t know how to load all the metadata for the Product entity. If you debug you will see that the ProductCategory DynamicControl column is not of type MetaForeignKeyColumn. After futher debugging you will see that much of the other metadata from the model is actually missing as well. Thankfully, the fix is very easy.

Change from:

protected void Page_Init(object sender, EventArgs e)
{
     FormView1.EnableDynamicData(typeof(MyDynamicDataExample.Models.Product));
}

to this:

protected void Page_Init(object sender, EventArgs e)
{
    // to get all the goodness like foreign-keys, etc we need to tell it to use our model
    FormView1.SetMetaTable(Global.DefaultModel.GetTable(typeof(MyDynamicDataExample.Models.Product)));
}

Also, from what I can tell the AutoLoadForeignKeys=”true” attribute of the DynamicDataManager has no bearing on whether the Drop Down List is populated or not.

You may have also noticed that the ProductCategory field when in ReadOnly mode shows a link with an number showing instead of the nice text description of the product category.  Luckily, this is an easy fix as well. In the AWDomainService.cs find we need to change the GetProducts() method to include the ProductCategory navigation property. This will cause the SQL that is generated to bring in the ProductCategory table.

Change from:

public IQueryable<Product> GetProducts()
{
    return this.ObjectContext.Products.OrderBy(o => o.Name);
}

to this:

public IQueryable<Product> GetProducts()
{
    return this.ObjectContext.Products.Include("ProductCategory").OrderBy(o => o.Name);
}

The change above will do the trick. However, if you are using this Domain Service with a Silverlight Client, you should also update the AWDomainService.metadata.cs such that the ProductCategory property on the ProductMetadata class has the Include() attribute. If you don’t have both of these Silverlight will not populate the ComboBox (assuming that is what you are using in Silverlight).

Change from:

[Display(Name = "Product Category")]
public ProductCategory ProductCategory { get; set; }

to this:

[Include()]
[Display(Name = "Product Category")]
public ProductCategory ProductCategory { get; set; }

You can download the complete source here.

Friday, April 29, 2011

Create CRUD UI using ASP.NET 4.0, FormView, Dynamic Data, DomainDataSource, Entity Framework, WCF Domain Service, LINQ, and custom validation – Part II

This is one entry in a series of blog entries:

Adding Labels based on MetaData from Model

In Part I we did some pretty neat stuff with Dynamic Data. In this blog entry I will show how to have your labels be set to what is set in the MetaData.

Let’s do some additional clean up here. Let’s remove the ProductCategoryID and ProductModelID fields since they will never be used.

Next we need to replace static text labels with a Label control so that we can set it via code. For example, replace ProductID with

<asp:Label ID="lblProductID" runat="server" AssociatedControlID="ProductIDDynamicControl"  OnLoad="LoadLabelForDynamicControl"></asp:Label>

I recommend a consistent naming convention to make remembering control ids. Once you have replaced one template such as the EditItemTemplate you can copy it to the InsertItemTemplate and the ItemTemplate, but be sure to change the Mode property to Insert and ReadOnly respectively.

Since we will have to get the metadata for each column on the FromView we will create a method that does this for us. Below is that method.

/// <summary>
/// Assuming you have a Label and DynamicControl (with the AssoicatedControlID on the label control set to the DynamicControl)
/// on your FormView it will set the text of the label control to the DisplayName which is from the MetaColumn for the column
/// used by the DynamicControl.
/// </summary>
/// <param name="labelControl">The label control that will have its text changed</param>
private void SetLabelBasedOnMetaData(Label labelControl)
{
           
    string dynamicControlID = labelControl.AssociatedControlID;
    if (string.IsNullOrEmpty(dynamicControlID)) throw new Exception("The AssociatedControlID must be set for Label control with ID: " + labelControl.ID);

    var container = labelControl.NamingContainer;
    var userControl = container.FindControl(dynamicControlID) as DynamicControl;
    if (userControl == null) throw new Exception("Could not find dynamic control with id: " + dynamicControlID);

    labelControl.Text = userControl.Column.DisplayName;
}

This will be called from the OnLoad event for each label.

protected void LoadLabelForDynamicControl(object sender, EventArgs e)
{
    Label labelControl = sender as Label;
    SetLabelBasedOnMetaData(labelControl);
}

If you run this now you will see that there is no real difference from the user’s perspective. However, the labels are being pulled from the MetaData (the Model). Now we just need to specify the label we want to display. This is the same label that is used in generated error messages.

 

To specify the labels, open the AWDomainService.metadata.cs and find the property you want to set the label for and add the following line.

[Display(Name="Product ID")]
public int ProductID { get; set; }

Do this for each property. Re-run and this time you will see that the labels are the values you set in the Display attribute.

It is a little more work, but in the end your labels will always be in sync from screen to screen and your error messages will reflect the name as well. When you need to make a change, you just do it once in your model. It is also the same information that your scaffolded screens will use as well.

 

All source for this project can be downloaded here.

Thursday, April 28, 2011

Create CRUD UI using ASP.NET 4.0, FormView, Dynamic Data, DomainDataSource, Entity Framework, WCF Domain Service, LINQ, and custom validation – Part I

This is one entry in a series of blog entries:

The title is a mouthful and thus the topic can be kind of overwhelming. With ASP.NET 4 there are so many different technology frameworks that you need to be familiar with. The problem that I have found is that most examples only use a one or two of these frameworks. In my world, I want to use them all and the examples are never as simple as the examples. In this blog entry, I will give a read world example of how to combine all these technologies. I find myself having to figure out how to do this over and over again. Hopefully, this will be of help to others.

This blog entry is NOT about how to create a Dynamic Data project in VS2010 and create an admin UI or something like that. This is about creating a page from scratch that uses this technology. To better understand the different scenarios that Dynamic Data can be used in and steps on how to extend it, see here.

Technology Overview

I am writing in the context of ASP.NET 4.0 and VS2010 (Visual Studio 2010). These technologies are relatively new in some cases and the api’s have changed since betas. I am only showing stuff that works in VS2010 (the final released version).

  • ASP.NET 4.0 – This is the version of ASP.NET that I am targeting.
  • FormView – This is the control that we will be using as a basis for the CRUD UI (User Interface).
  • Dynamic Data – This is the technology that allows you to use DynamicControl on your FormView instead of the standard ASP.NET Forms controls. BTW, you don’t have to have anything installed (not even the Dynamic Data files and templates). You get basic implementation without them, but with them you can customize and get a more full-featured set of tools. See here for a GREAT video on using Dynamic Data in “old” applications that don’t have all these cool technologies. For the most up to date resources, click here.
  • Entity Framework 4.0 – The standard with VS2010 for database to object mapping. Click here if you want to see how to use Dynamic Data with an ObjectDataSource and GridView.
  • WCF Domain Service – This is your middle tier where you would put your business logic, complex validation, etc. It provides a consist way to access your perform CRUD operations on your data. Abstraction layer before the Entity Framework.
  • LINQ – We will use LINQ to Entities in the WCF Domain Service to query database through the Entity Framework.
  • DomainDataSource – This is a control that works much like the ObjectDataSource or LinqDataSource or EntityDataSource except that it can connect to your WCF Domain Service from ASP.NET. Please note that there is also one for Silverlight and it has the same name so when you are Googling be sure to check what the context is. This is a good doc on using this control.

Getting Started

You can select most any type of web application project in VS2010 to get started. My instructions will be for the Dynamic Data project so that I don’t have to explain how to manually move over the Dynamic Data files. If you have an existing project and need to copy over the Dynamic Data files, click here for detailed instructions. Please note, I have copied some of these steps (and written others) from instructions I have read on MSDN, but have combined them together in one continuous instruction set. For example, most of the instruction are from: here and here.

  1. Open Visual Studio 2010 and create a new project of type ASP.NET Dynamic Data Domain Service Web Application. I’m calling my project MyDynamicDataExample.
  2. Optional - Create two Directories: Models and Services.
  3. Optional - Download and install the AdventureWorksLT database if you don’t already have it. The particular database is not really that important to understand the concepts. Notice I am using the Lite version since it is a bit simpler to follow, etc.
  4. Add a New Item… and select ADO.NET Entity Data Model. I called MyModel.edmx. We will generate from Database. Select the database you want to work with (add a new connection if it is not there). On the Choose Your Database Objects screen, select Product and ProductCategory. Keep everything else default.
  5. You must build your project so that the next step will work.
  6. Add (to Services folder) a New Item… and select Domain Service Class. I called mine AWDomainService.cs. Select the options as shown below:
    image
  7. Add (to Models folder) a New Item… and select Web Form using Master Page. Call it DDTest.aspx. Select the Site.master on the next screen.
  8. From the General or Data group of the Toolbox, add a DomainDataSource control to the page. If you have never used the DomainDataSource before you will need to add it to your toolbox. To add it to your toolbox. Click the Tools menu, and then click Choose Toolbox Items. In the Choose Toolbox Items dialog box, click the .NET Framework Components tab, select the DomainDataSource check box, and then click OK.
  9. Add a DomainDataSource to the page. Configure the datasource to point to GetProducts() method on the service you created. Enable Inserts, Updates and Deletes.
  10. Add a QueryExtender to the page. Set the TargetControlID to the id of the DomainDataSource (mine is called DomainDataSource1).
  11. Add a FormView (though a GridView or DetailsView could also be used). Check the Enable Dynamic Data Support checkbox. Please note it will not stay checked when you come back to it later (in some cases). Set the Data Source to the DomainDataSource you added earlier.
  12. Add a DynamicDataManager control to the page. Chose Register Controls… and add the FormView as shown below.
    image
    This registers the data-bound control and enables dynamic behavior for it.

  13. Open the code-behind. Add a Page_Init method and add the following line:

    protected void Page_Init(object sender, EventArgs e)
    {
        FormView1.EnableDynamicData(typeof(MyDynamicDataExample.Models.Product));
    }

  14. Go to the .aspx page again and go to the Source view. Find the QueryExtender you added earlier. Add the following line to it:

    <asp:QueryExtender ID="QueryExtender1" runat="server" TargetControlID="DomainDataSource1">
            <asp:DynamicRouteExpression ColumnName="ProductID" />
    </asp:QueryExtender>

    This will allow us to pass the ID that we want to edit via the url as a query string.

  15. Now we need to do some clean up. In each of the templates in the FormView remove the Text and Dynamic controls for: ProductCategoryReference, EntityState, and EntityKey. Also, remove the rowguid from the insert template.

  16. Let’s test to see if this works now. You will see that you get the YSOD (Yellow Screen Of Death) when you click the Edit button and then the Update button. You will get an EntityOperationException and the last method that was called was HandleValidationErrors. This means that something in the model failed.

  17. Create event handlers on the DomainDataSource for the Updated and Inserted events. They should look like this when you are done:

    protected void DomainDataSource1_Inserted(object sender, Microsoft.Web.UI.WebControls.DomainDataSourceStatusEventArgs e)
    {
        if (e.ChangeSetEntry.HasError)
        {
            foreach (var error in e.ChangeSetEntry.ValidationErrors)
            {
                AddValidationSummaryItem(error.Message);
            }
        }
    }

    protected void DomainDataSource1_Updated(object sender, Microsoft.Web.UI.WebControls.DomainDataSourceStatusEventArgs e)
    {
        if (e.ChangeSetEntry.HasError)
        {
            foreach (var error in e.ChangeSetEntry.ValidationErrors)
            {
                AddValidationSummaryItem(error.Message);
            }
        }
    }

  18. Next add this supporting method.

    public void AddValidationSummaryItem(string errorMessage)
    {
        var validator = new CustomValidator();
        validator.IsValid = false;
        validator.ErrorMessage = errorMessage;
        this.Validators.Add(validator);
    }

  19. Now put a breakpoint on the Updated event handler and debug your application. Do the same test again, you’ll see there is some error about the field: ThumbnailPhoto. Note that the error does not display on the page, but it doesn’t go to the YSOD either. Like any other validation exception that is NOT column specific, we need to use the ValidationSummary control to view this error.

  20. Drag a ValidationSummary control to your page. Re-run and you’ll see the exception. This does give little bit of database schema information. This may be considered by some to be bad. I’ll leave that up to you. If you don’t do this then you won’t get validation exceptions that are thrown from your domain service which is how you will implement your business logic. My experience shows that nothing too serious comes out of here once you have everything wired up correctly. If you don’t like that you’ll have to come up with another solution.

  21. Let’s quickly fix this by removing the ThumbNailPhoto field from each of the FormView templates. Re-run, and this time you won’t get any errors. We can do this because it is an optional field.

  22. Let’s add some validation to see how to do that. Go to the AWDomainService.cs and find the UpdateProduct method. Modify it so that it looks like this:


    public void UpdateProduct(Product currentProduct)
    {
        this.ObjectContext.Products.AttachAsModified(currentProduct, this.ChangeSet.GetOriginal(currentProduct));
        if (currentProduct.ListPrice < 2000)
            throw new ValidationException("List Price is too low.");
    }
    Re-run, change the List Price to less than 2000 and update and you’ll get the message shown in the ValidationSummary control.

  23. You can also use ValidationAttributes such as Required, Range, RegularExpression, etc in the Model to declaratively validate the data. To do this open your AWDomainServices.metadata.cs. Find the StandardCost property and modify it so that it looks like this:

    [Range(0, 200, ErrorMessage="{0} must be between 0 and 200.")]
    public decimal StandardCost { get; set; }

    Re-run and and change the standard cost to something greater than 200 if it isn’t already and Update. You’ll see it says StandardCost must be between 0 and 200. Notice it filled in the name of the field for us. It is the actual property name though.

  24. To display a user-friendly version of the property name you can add Display information as shown below.

    [Display(Name="Standard Cost")]
    [Range(0, 200, ErrorMessage="{0} must be between 0 and 200.")]
    public decimal StandardCost { get; set; }

    Re-run and you’ll see the same message but with the friendly name of the property.

  25. To Edit a particular record such as the Product with ID = 800, just go to the same url, but with DDTest.aspx?ProductID=800.

  26. If you try to run your application without specifying the specific test page you will get an error like this “There are no accessible tables. Make sure that at least one data model is registered in Global.asax and scaffolding is enabled or implement custom pages.”

    To fix that you just need to go to your Global.asax.cs and uncomment the line that start with DefaultModel.RegisterContext. Change it so that it looks like this:

    DefaultModel.RegisterContext(new DomainModelProvider(typeof(MyDynamicDataExample.Services.AWDomainService)), new ContextConfiguration() { ScaffoldAllTables = true});

    When you do this you’ll have some CRUD pages for each of the tables you included. This is separate from what we are doing here which is a custom page, but let’s fix the errors anyway. Another option would be to not have this default page and leave that line above commented. That way you won’t have all these admin page open to the world. Yes you can secure them, but they are not by default.

  27. Back on track, when you access the Default.aspx page you will get an error like this: The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip'.

    To fix this just go to the AWDomainService.cs and add a sort method to the default query methods which are GetProducts and GetProductCategories. Just make the methods look like these:

    public IQueryable<ProductCategory> GetProductCategories()
    {
        return this.ObjectContext.ProductCategories.OrderBy(o => o.Name);
    }

    public IQueryable<Product> GetProducts()
    {
        return this.ObjectContext.Products.OrderBy(o => o.Name);
    }

  28. Re-run. This time go to the Product link. The same validation we added before is also here. This is because the validation is written at the Model, not the UI. This is AWESOME in my opinion. I love it. This is why I love Dynamic Data.

I hope this has been beneficial to all.

The entire source for this example (minus the AdventureWorksLT database) can be downloaded from here.

Tuesday, April 26, 2011

AzGroups 8th Annual Scott Guthrie Event

Things to check out:

NUGET

(pronounced NEWGET) – it is built into VS2010 (Visual Studio 2010) and makes finding, downloading, and installing libraries (open source included) into your project. It even does some configuration in the config files, etc. Pretty awesome. You can get it here.

elmah

It is an error logging facility that is completely pluggable that can added to a running ASP.NET web application without re-compilation or deployment. When an exception occurs it logs it, but allows you decide where to log it to such as a database, RSS, email, etc. It also records A LOT of VERY useful information for determining what happened.  See here for more details.

IIS Express

Can be used side-by-side with the built in web server (Cassini) in VS2010. It launches fast just like the web server built into VS2010, but doesn’t require you setup virtual directories, etc like you do with IIS (full version). You now get best of both worlds. It now let’s you develop using the IIS 7.x feature-set. It is now as easy to use as the web server built into VS2010. It doesn’t require admin account. You don’t have to change any code or the way you work to take advantage of it. See Scott’s blog for more details.

Web Matrix

You should still continue to use Visual Studio for professional work, but Web Matrix project are great for hobby, family sites, etc. It has been totally reworked to be a task based tool. It makes publishing very easy. If the site gets more complex the project can be opened up in Visual Studio.

SQL Server Compact Edition 4

It is great for ASP.NET development. It is light weight and free. It is an embedded database (no SQL Server required) so it is in the binaries (bin directory) that you can xcopy to your server. You can use Standard SQL Server syntax so anything that supports the ADONET provider model (such as LINQ and EF) will work. You are also licensed to redistribute it. All this means you can now deploy this in a medium trust ASP.NET shared web hosting such as DiscountASP, GoDaddy, etc. This means you don’t have to pay for the SQL database. It integrates into VS2010 (coming soon). It is different from previous version because it is safe to use with multi-threaded environments (such as ASP.NET). and no longer blocked from being used with ASP.NET. The catch is that it is for light-usage production (4GB or less for datafile) usage scenarios and it does NOT support stored procedures. For high-volume usage usage, you’ll probably want to use SQL Server Express (which is still free), SQL Server, or SQL Azure. Also, since stored procs are not supported the ASP.NET Membership is not supported (though they will be shipping new providers so that they do). The only change to your code when you migrate is your configuration string. See Scott’s blog for more details.

 

Portable Library Project

It is a special kind of project in VS2010 that only allows code that will work on particular targets. In particular, the targets are Silverlight and Silverlight for Window Phone 7. Intellisense only lets you see Intellisense on methods, properties, classes, namespaces, etc that are compatible with both. The most I could find on it was here.

Silverlight 5

Great stuff coming with Silverlight 5. Better DataBinding support for MVVM. Improved Printing and Text. Finally there will be a 64-Bit version of Silverlight. 3D Modeling that use Hardware acceleration. 3D and 2D can be used together. Breakpoints on XAML Bindings.

MVC 3

I am really impressed with MVC3. I am very tempted to try a project with MVC3. It takes advantage of HMTL 5 including Data validation, round corners, etc.

MVC Basics

The basic idea is that a url is mapped to a controller and method on that controller. That method makes calls to the model where most of the business logic resides, and then typically returns a view which is responsible for rendering the response (page). It maps url to action methods on controller class. In general the best practice with MVC is to have skinny controllers and fat models. Default method is called Index() and is called when no action is specified. Can pass entities as parameters to methods; just need to map them. Default parameters can be used as well. (i.e. int num = 5). ASP.NET MVC forces separation, while ASP.NET Forms does not.

Routing

When determining which rule matches it starts with the one that was added first. It then proceeds down the list until one matches. Routing is used to map urls to controllers and actions, but it is also used to generate urls in the application.

Glimpse

It is a an open source tool that allows you to diagnose what is happening on the server, but from the client. It is very useful when trying to figure out what happened once your request made it to the server. For example, what route was executed. It is basically Fiddler for the server.

For more information see here.

Razor

It is a View Engine for MVC. For more info see ScottGu’s blog. Razor files are .cshtml. Tags start with @ and it automatically figures out where code ends and content begins. Content and code can be intermingled. A layout page is basically like a master page in ASP.NET Forms. You can use traditional parameters or Named parameters. Use Custom helpers for custom rendering; refactoring in a way.

MVCScaffolding package

It is a code generator for MVC; a smart one at that. Highly recommended so you don’t have to write so much code to do CRUD UIs. Use NuGet Package Manager to get and install it.

Entity Framework 4.1

Great code first support. You can use POCO objects, make changes and the database just updates. It is so cool. This behavior is optional, but very nice. You can setup database initialization code to populate some basic data when the database is dropped.

Modernizr

A great tool that allows you to take advantage of HTML 5 when it is available and downgrade when it is not. An example of this is round corners. Very nice tool that can be used in most any ASP.NET project. http://www.modernizr.com/

Windows Phone 7

Later this year there will be a new release called Mango. It is a very exciting release as it will bring the Windows Phone 7 much closer to the competition as far as its offering. To get started with Windows Phone 7 development go here. Everything that is developed for Windows 7 Phone falls into two categories: Silverlight or XNA. XNA is for games (also used for XBOX), and Silverlight is for everything else. You can import some XNA libraries (such as audio) into Silverlight. Tombstoning is basically storing state to appear like the application never quit when in fact it did. It basically works by providing a state bag that most anything can be written/read to when different events such as (navigate to and from are called). It works much like Viewstate does in ASP.NET except it is not automatic. So more specifically it works like adding and retrieving stuff to/from viewstate in ASP.NET. The cost is $99 per year to put your application (or as many as you want except not more than 15 free ones) in the Marketplace. You can register to developer unlock your Windows Phone 7. Visual Studio 2010 comes with an emulator, but the one that will be in the mango release is sooo much better because it simulates things like sensors. The talk was given by Jeff Wilcox.

Tips on Windows Phone 7 development

Change splashscreen (an image) to all black if you app launches immediately. That way it is perceived as faster and cleaner. If your app takes a few seconds to load then put in a custom splashscreen (change the image) to give a more professional look. Add scrollviewer or list so that scrolling will always be available if something doesn’t fit on the screen. Use the metro look and feel styles, don’t hard code styles. If things don’t align as expected, then use 12px margins. Promote your app by creating a site for it. Prompt a user for review of your app after you think they have used it for a while. Statistically most apps are only used once and never used again. Use Watson to collect crash information, bugs, etc. Use Google Analytics to track page navigation within your app. Keep your main dll as small as possible since the entire thing is checked before loading into memory. Delay load pages / dlls on an as needed basis to help accomplish this. This also helps with startup times. Use a tombstoning helper. Use caching whenever possible.

Windows Azure – by Scott Guthrie and Mark Russinovich

Windows Azure is a great technology that needs some work with regards to deployment speed, and in general ease of use, but it is extremely well architected for scaling your application in a very elastic way. It allows you to worry about your app and not the infrastructure it is running it. It is Microsofts offering of cloud computing. The idea is that if you need 100 servers for an event you have them. Then after the event you don’t need them. With traditional models you would have to have servers ready to go at all times and pay for that much power. Since Microsoft has a giant server farm called Windows Azure and a middle tier between you and the server OS you only pay for what you use for the length of time you use it. Everything is continually monitored for 99.? uptime.

Mark went into all the details or the architecture. He convinced me it is very complex and robust, but not so fun to listen to a discussion about it. way too much details for my interest level. However, here as some of the things I found interesting. SQL is actually much slower than the way Windows Azure does it. They actually have everything as read only. Once it is read the objects are de-serialized and used. If they need to update, they are written back to the cloud as serialized objects. This takes only a trillionth of a second instead thousandths of a second that SQL takes. This allows them to scale fast. Their belief is that in the next 10 years or so this will scenario will be common more so than the relational database. Currently options in Azure are SQL, Blobs, and Queries. I believe SQL Azure is part of Windows Azure.

Some Barriers / solutions to get over before cloud computing will be accepted are: Trust of proprietary data being outsourced; loss of control; confidence (ISO and other certifications will help); Private clouds may be an alternative; license to run in own data center may help also.

Thursday, March 3, 2011

Automatic Auditing of Changes using Domain Service and Entity Framework

A special thanks to Fredrik Normen for providing the basis for my code. His great article is here. For a better understanding of the basic code, please read Fredrik’s implementation first. He does a good job of walking you through his code.

With that said I have changed most of his code and added logging to a database table using another Entity Framework (EF) model. You can download my updates to his code under the Source Code section.

Please note that only changes made through the Domain Service will be logged. If you don’t use a Domain Service to modify all your data that you want logged this solution is probably not for you. However, if you use a Domain Service and Entity Framework this is a pretty robust solution for adding auditing to your ASP.NET web application in minutes. I am using this with my Dynamic Data web application and it works great!

The code works because the Domain Service has a concept of a ChangeSet. When you save (update or insert or delete) a ChangeSet is created that basically shows what the original entities look like and what the current entities look like. This is all standard Domain Service stuff. Nothing I did. However, what I do is look at the original and current values and create EntityChangeInfo objects and PropertyChangeInfo objects. These then get written to the database where there is a record in the database for each field. This is very verbose for Inserts and for Deletes, but just write for Update. If you don’t need insert and delete auditing, you can easily comment them out.

To implement my solution, here are the basic steps (from my memory) to add auditing to you application.

  1. Download and use the AuditLog-Create.sql to create an AuditLog table in a database.
  2. Create an Auditing directory in your Services directory (if you have one).
  3. Download and copy the AuditLogger.cs, ChangeSetHelper.cs, EntityChangeInfo.cs, PropertyChangeInfo.cs to the Auditing directory you just created.
  4. In your Models directory (if you have one) create a new ADO.NET Entity Framework Data Model that points to the database where you created the AuditLog table. Call the model AuditModel. The only table you want to add to it is the AuditLog table. You don’t need a Domain Services or anything else for this. We will reference it directly.
  5. Download and copy the snippet from the DomainService-PersistChangeSetSnippet.cs and paste it in your domain service file that you already should have in your project. This is the file for the domain service that you want to audit. If you don’t want INSERT or DELETE auditing you can comment out the appropriate line in this snippet.

That is it. You should now be able to run your application, make some changes and see the changes show up in the AuditLog table.

You can then execute a query something like this to see the history of a particular record in a table.

select * from auditlog where EntityName = 'Activity' and EntityPKValues = '46' and operation = 'Insert'

select * from auditlog where EntityName = 'Activity' and EntityPKValues = '46' and operation = 'Update'

select * from auditlog where EntityName = 'Activity' and EntityPKValues = '46' and operation = 'Delete'

My Comments

You may notice that I log my times in UTC and that the date/time is the same for a given update, insert, or delete. In other words, when an update is written to the database, multiple records are created (one for each column that changes), but the CreatedDateTimeUTC field is stamped with a ONE datetime.

When values are inserted, the OriginalValue column will ALWAYS blanks. When a record is deleted, the CurrentValue column will ALWAYS be blank.

If you have a properties that you have added to an entity they will have an initial value and the computed value in some cases. If this is the case for you, you may want to hard code these property names the ChagneSetHelper.GetPropertiesChangeInfo method as properties to not log. Just like I have done for the EntityState property. Up to you.

Source Code

AuditLog-Create.sql

AuditLogger.cs

ChangeSetHelper.cs

EntityChangeInfo.cs

PropertyChangeInfo.cs

DomainService-PersistChangeSetSnippet.cs

Wednesday, February 9, 2011

Setting default values in Entity Framework when using Silverlight

I found myself amazed at how difficult it is to set default values for a property in the Entity Framework (even version 4) when used with Silverlight. Ideally I could use the DefaultValue attribute in the metadata class for my model. The problem is that Silverlight doesn’t use it. It seems to work ok in my tests that don’t use Silverlight if I remember correctly. But that only partially helps. I explored putting the value in the constructor for the entity that has the property I want to set the default value on, but that fires every time the object is created. This means that it was created even when displaying the results of a query, which is not the event I was hoping for. I want the default value to be used when a new entity is created, but just the object instantiated.

Then I ran across this post. It talks about creating a partial class on the client-side (Silverlight) and using the partial method called OnCreated(). The forum seems to say that you can define the OnCreated() partial method in the partial entity class that is on the server-side, but that method is not defined on the server-side that I can tell. So, the partial keyword doesn’t work in that context. The server-side object has a .shared.cs instead of just .cs extension so the file will be copied to the client-side. The problem is that the code has to work on the client and the server side. As noted before, the OnCreated method only exists on the client-side.

The solution is actually quite simple. I just had to explicitly define a partial class on the client-side even though I already have one on the server-side and is shared. This allows me to leverage the OnCreated partial method on the client that will fire when the entity is created, not just instantiated, and still keep my shared partial class that is on the server and client side.

I haven’t tried it, but by doing like Kyle recommends I should be able to use the DefaultValue attribute in the metadata and have it carry over to the client-side by calling the utility method that reads the DefaultValue attribute from the model when the OnCreated method is called.

So, here is an example, of what I am trying to explain.

In this example (to keep with the example on the forum) my entity is called Entity1

In my Silverlight project, I define a file called Entity1.cs. It would contain:

public partial class Entity1
    {
        partial void OnCreated()
        {
            DefaultValueUtility.InitializeDefaultValues(this);
        }
    }

NOTE: I could also just set the property directly instead of pulling the data from the model.

I can, but don’t have to have a file called Entity1.shared.cs on my server-side that will can contain whatever I want it to. It will be copied to the client-side as well. Then it will be merged with the Entity1.cs and the generated Entity1 file from the model itself on the client side because they are all partial classes.

Here is the code for the DefaultValueUtility call above. You will want to put this code somewhere in your Silverlight project.

using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;

namespace DefaultSetter
{
    public static class DefaultValueUtility
    {
        public static void InitializeDefaultValues(object entity)
        {
            PropertyInfo[] properties = entity.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
            {
                MethodInfo propertySetter = property.GetSetMethod();
                if (propertySetter != null)
                {
                    DefaultValueAttribute defaultValueAttribute = (DefaultValueAttribute)
                        property.GetCustomAttributes(typeof(DefaultValueAttribute), true).FirstOrDefault();

                    if (defaultValueAttribute != null)
                    {
                        object defaultValue = 
                            Convert.ChangeType(defaultValueAttribute.Value, property.PropertyType, CultureInfo.InvariantCulture);

                        propertySetter.Invoke(entity, new object[] { defaultValue });
                    }
                }
            }
        }
    }
}

Monday, October 18, 2010

Working with Dynamic Data Controls: Finding, Set Value, Get Value

Once you start working with ASP.NET, FormView, and the DynamicData controls you will soon learn that it isn’t as convenient to get and set values as you might like. You may also want to find controls not by their name, but by the column / property that they are bound to in the ADO.NET Entity Model.

I have put together some extensions to the Control class that make doing all these things much easier. All you have to do is create a class in your project called ControlExtensions. Copy and paste the code below into it. Change the namespace as needed. Then on the page you want to use it, just include the namespace. Then when you look at the methods on any control you will see the methods below. I have tested the code below with a FormView and also with DynamicControls on a User Control  that is then on a FormView. In both cases, the code works well.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.DynamicData;
using System.ComponentModel;

namespace DistiPromo.Helpers
{
    public static class ControlExtensions
    {

        /// <summary>
        /// This will find the Dynamic Data control for the specified column (name from Entity model)
        /// </summary>
        /// <param name="control">the control (such as FormView or UserControl) that directly contains the control you are looking for</param>
        /// <param name="columnName">the name of the column (from the Entity Model) that you are looking for</param>
        /// <returns>The DynamicData Control for the column that you are looking for</returns>
        public static Control FindFieldTemplate(this Control control, string columnName)
        {
            // code copied from internal method: System.Web.DynamicData.DynamicControl.GetControlIDFromColumnName
            // Since it is internal, it could change, but I needed to get to it
            return control.FindControl("__" + columnName);
        }

        public static FieldTemplateUserControl FindFieldTemplateUserControl(this Control control, string columnName)
        {
            var userControl = ((FieldTemplateUserControl)(control.FindFieldTemplate(columnName)));
            if (userControl == null) throw new Exception("Could not find FieldTemplate in Control for " + columnName);
            return userControl;
        }

        public static Control FindControlForColumn(this Control control1, string columnName)
        {
            var control = FindFieldTemplateUserControl(control1, columnName).DataControl;
            if (control == null) throw new Exception("Could not find control in Control for " + columnName);
            return control;
        }

        public static T FindControlForColumn<T>(this Control control, string columnName) where T : Control
        {
            return FindControlForColumn(control, columnName) as T;
        }

        public static object GetValueForColumn(this Control control, string columnName)
        {
            var actualControl = FindFieldTemplateUserControl(control, columnName).DataControl;
            return GetValue(control, actualControl);
        }

        public static T GetValue<T>(this Control control, string columnName)
        {
            object rawVal = GetValueForColumn(control, columnName);
            //return (T)Convert.ChangeType(rawVal, typeof(T));

            // this is a little better because it handles nullable types also
            return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(rawVal);
        }

        public static T GetValue<T>(this Control control1, Control control)
        {
            object rawVal = GetValue(control1, control);
            //return (T)Convert.ChangeType(rawVal, typeof(T));

            // this is a little better because it handles nullable types also
            return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(rawVal);
        }

        public static object GetValue(this Control control, Control actualControl)
        {
            if (actualControl is ITextControl)
            {
                return (actualControl as ITextControl).Text;
            }
            else if (actualControl is ICheckBoxControl)
            {
                return (actualControl as ICheckBoxControl).Checked;
            }
            else if (actualControl is ListControl)
            {
                return (actualControl as ListControl).SelectedValue;
            }
            else if (actualControl is HiddenField)
            {
                return (actualControl as HiddenField).Value;
            }
            else throw new Exception("Could not get value of unknown control type: " + actualControl.GetType().ToString());

        }

        public static void SetValue(this Control control, string columnName, object value)
        {
            Control actualControl = FindControlForColumn(control, columnName);
            SetValue(control, actualControl, value);
        }

        public static void SetValue(this Control control, Control actualControl, object value)
        {

            if (actualControl is ITextControl)
            {
                (actualControl as ITextControl).Text = Convert.ToString(value);
            }
            else if (actualControl is ICheckBoxControl)
            {
                (actualControl as ICheckBoxControl).Checked = Convert.ToBoolean(value);
            }
            else if (actualControl is ListControl)
            {
                (actualControl as ListControl).SelectedValue = Convert.ToString(value);
            }
            else if (actualControl is HiddenField)
            {
                (actualControl as HiddenField).Value = Convert.ToString(value);
            }
            else throw new Exception("Could not set value of unknown control type: " + actualControl.GetType().ToString());
        }
    }
}

Friday, October 15, 2010

Lessons in Dynamic Data, Domain Service, and DomainDataSource with ASP.NET 4

I have been working with Silverlight a lot lately and have come to love the Domain Service. I recently started a new ASP.NET based project and saw that in VS 2010 I can now create an ASP.NET Dynamic Data Domain Service Web Application. So, I tried it.

I have learned some things since I did this. Below is what I have learned.

Getting Started, Docs, etc.

  • For a good starting point to learn about Dynamic Data, click here.
  • Here are the best docs I can find for looking at lot of scenarios and customizations you may want to do with Dynamic Data. I recommend reading this.
  • There is sample code that is referenced in the docs above. I think the code may be a bit out of date though. Anybody know where newer sample code is?
  • Here is the Dynamic Data forum if all else fails.
  • Once you create a new project in Visual Studio 2010 the project does run. You need to do a few things first like create your model and Domain Service. This walks you through what you need to do.

Gotchas

  • If you create a custom page, you MUST have all the REQUIRED fields on the FormView in Edit mode, otherwise, the form will give your an error when you click the Update button. Click here for more details on this issue. Workarounds include setting Visible to false or creating a new FieldTemplate  or modify the existing implementation. Click here for details on how this can be done.

  • I tried to create a total independent page that uses the DynamicDataSource, a form view, and my Domain Service Class and it will not work. It can’t figure out the MetaData it needs to work. The solution is to create a directory under DynamicData\CustomPages. The name should match the name of the Entity (not Entity Set). Hint, the name is the singular, not plural if version usually. To create a custom Edit page for your entity, copy DynamicData\PageTemplates\Edit.aspx (and the .aspx.cs file) to the directory you created above. Correct the class names, etc and you should be in good shape. For more details, try here.
  • If you create a custom page in the DynamicData\CustomPages\<YourEntity>\Edit.ascx for example don’t use FormView1.FindControl() in the Page_Load() event. If you do it will cause the DropDownLists to not have an item selected in them. I am guessing it is just early for stuff that DynamicData is doing since if you look in the FieldTemplates a lot of stuff such as binding, etc takes place in the PageLoad event. My solution was to use the PreRender event to put my stuff there. That seems to work fine. No issues yet. :)

Here are some differences between the ASP.NET and Silverlight experience.

  • The Domain Service is actually a Domain Service CLASS in ASP.NET and doesn’t use WCF or anything like that from what I can tell. In Silverlight it is actually a Domain SERVICE and actually uses WCF under the hood to communicate with your Silverlight application.
  • I don’t seem to have to use .Include(“…”) queries in the Domain Service and [Include()] in the MetaData to make the ADO.NET Entity Framework pull in my related entities.

Thursday, October 14, 2010

DomainDataSourceView.PerformCudOperation error on updating a FormView.

If you have a REQUIRED field in your ADO.NET Entity Model, you MUST have it on your Form when you use the DomainDataSource, FormView, and Domain Service Class and it must be EDIT mode if you are using the DynamicDataControl. If you leave it off the form or set the mode to ReadOnly you will get a totally useless error like this.

[EntityOperationException: An error has occurred.] Microsoft.Web.UI.WebControls.DomainDataSourceView.PerformCudOperation(ChangeSetEntry operation, Action`1 operationPerformingEvent, Action`1 operationPerformedEvent) +331 Microsoft.Web.UI.WebControls.DomainDataSourceView.UpdateObject(Object oldEntity, Object newEntity) +195 System.Web.UI.WebControls.QueryableDataSourceView.ExecuteUpdate(IDictionary keys, IDictionary values, IDictionary oldValues) +115 Microsoft.Web.UI.WebControls.DomainDataSourceView.ExecuteUpdate(IDictionary keys, IDictionary values, IDictionary oldValues) +40 System.Web.UI.DataSourceView.Update(IDictionary keys, IDictionary values, IDictionary oldValues, DataSourceViewOperationCallback callback) +95 System.Web.UI.WebControls.FormView.HandleUpdate(String commandArg, Boolean causesValidation) +1154 System.Web.UI.WebControls.FormView.HandleEvent(EventArgs e, Boolean causesValidation, String validationGroup) +408 System.Web.UI.WebControls.FormView.OnBubbleEvent(Object source, EventArgs e) +95 System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +37 System.Web.UI.WebControls.FormViewRow.OnBubbleEvent(Object source, EventArgs e) +112 System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +37 System.Web.UI.WebControls.Button.OnCommand(CommandEventArgs e) +125 System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +167 System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +10 System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +13 System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +36 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5563

If you are lucky the field you set to ReadOnly will be a DataTime field or something and it will tell you that the date is not valid. If it is just a string field then you may get the useless error as shown above.

This probably won’t show up unless you try to create a Custom Page for one of your entities. The nice thing is that when you create a Custom Page you get full control over the layout of your entity. The problem is that you can create all kinds of frustrating issues like this one.

BTW, this is only an issue for datatypes that use the Text.ascx and DateTime.ascx controls. The reason is because these controls are implemented using a literal control instead of a Label, etc which has viewstate. Any datatype that has a _Edit.ascx counterpart won’t be affected and also any that have something that has viewstate as the underlying readonly implementation.

Work Arounds

Work Around – If you don’t want the user to see a field

You can always add the control to the FormView even if you don’t want the user to see it. The set the visible to false. This will allow it to work properly. All form validators will not be created which is good in for the most part.

If you are just doing an edit template then the above will work fine. However, if you are doing an insert template, then you will get errors about not being able to set the value because the value is illegal or invalid. An example of this is a DateTime can’t be set to null or an int can’t be set to null. If the field is required then non-nullable types will be used. This means you need to specify a default value.

The trick to specifying the default value is that you can’t do it in your entity’s constructor because since the FormView has the required field on the EditTemplate a value (null) will be set on your Entity after it is created (after the valid value you may have tried to default in the entities constructor. That is what is causing the error.

One solution is to use the ItemInserting event of the FormView. Here you will find a parameter that is of type FormViewInsertEventArgs. It has a collection of all the values that are being submitted.

For each of the items you added to the FormView and hide, you will need to set the default value they should have using the Values collection. The key is the name of Entity Property you bound to in the FormView. The exception to that is if you re binding to a Navigation property such as with a DropDownList. In this case the foreign key is actually what you will find in the Values collection, not the Navigation property name. The value is foreign key, not the related entity.

If you don’t want to think that hard, you can always just set the values of the DynamicControls you want to default using what ever method gets called when you click your insert button. In my case, I am going with the same LinkButtons that are used in the default insert template for Dynamic Data. This means that FormView1_ItemCommand is a good place to set the values of your DynamicControls. This is a bit easier because you don’t have to worry about DropDownLists in the same way. However, since you are dealing with different controls that is more thought also, so it is really up to you on which approach you want to take. The bottom line is that the value has to be there when the FormView passes it on to the DomainDataSource.

FYI, I have made working with DynamicControls must easier. It makes setting and getting values on forms that have DynamicControls on them trivial. Here is an example of what I am talking about.

FormView1.SetValue("DateCreatedUtc", DateTime.UtcNow);

Here is the link to the source code. I implemented it as an extension of the Control class.

Work Around – If you want it on the Edit mode of the FormView, but show as readonly.

Option 1

If you need the field on the FormView, but want it to be readonly when the FormView is in Edit mode, there is another solution.

Copy DyanmicData\FieldTemplates\Text_Edit.ascx (and the .ascx.cs file) to DyanmicData\FieldTemplates\TextAppearReadOnly_Edit.ascx (and .ascx.cs file). What comes before the underscore is not important, but what the name must end is _Edit.ascx and _Edit.ascx.cs.

Remove the validator controls as they are not needed. Add a literal control and bind it to the same value as the TextBox. Once you have done that, your .ascx file will look something like this:

<asp:Literal runat="server" ID="Literal1" Text="<%# FieldValueEditString %>" />
<asp:TextBox ID="TextBox1" runat="server" Text='<%# FieldValueEditString %>' ReadOnly="true" Visible="false" />

Now open the .ascx.cs file. Remove all items that aren’t needed or don’t compile. You class will look something like this:

public partial class TextAppearReadOnly_EditField : System.Web.DynamicData.FieldTemplateUserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        TextBox1.ToolTip = Column.Description;
    }

    protected override void ExtractValues(IOrderedDictionary dictionary)
    {
        dictionary[Column.Name] = ConvertEditedValue(TextBox1.Text);
    }

    public override Control DataControl
    {
        get
        {
            return TextBox1;
        }
    }

}

Now, where ever you want a read only field on do something like this:

<asp:DynamicControl ID="DateCreatedDynamicControl" runat="server" DataField="DateCreated" Mode="Edit" UIHint="TextAppearReadOnly" />

The part to pay attention to is that the Mode is set to Edit and the UIHint specifies to use our control we created.

Option 2

I actually prefer this method as the semantics of option 1 don’t seem quite right. In this option, we will actually modify the default controls to implement what I call a bug fix. :)

  1. Open DynamicData\FieldTemplates\DateTime.ascx
  2. Change the line:

    <asp:Literal runat="server" ID="Literal1" Text="<%# FieldValueString %>" />

    to

    <asp:Label runat="server" ID="Label1" Text="<%# FieldValueString %>" />

    Notice the only change I made is changing the type from Literal to Label and updated the ID to reflect the change also.
  3. Open DynamicData\FieldTemplates\DateTime.ascx.cs
  4. Add the following method:
    protected override void ExtractValues(IOrderedDictionary dictionary) {
                dictionary[Column.Name] = ConvertEditedValue(Label1.Text);
    }

  5. Add the DataControl property (or modify it if it already exists) as shown below

    public override Control DataControl { get { return Label1; } }

Do the Same for Text.ascx (and Text.ascx.cs).

Using this fix, you don’t have to change any of the properties on the DyanmicControl and the semantics are right. Here is an example of what you may have.

<asp:DynamicControl ID="DateCreatedDynamicControl" runat="server" DataField="DateCreated" Mode="ReadOnly" />

Notice that the Mode is ReadOnly which makes sense to me. This means that you can use the DynamicControl exactly the same regardless of the datatype and regardless of whether it is a required field or not.

Thursday, July 8, 2010

Unable to update the EntitySet 'MyEntity' because it has a DefiningQuery and no <InsertFunction> element exists in the <ModificationFunctionMapping> element to support the current operation.

If you are using the ADO.NET Entity Framework and a Domain Service (I don’t think you have to be using a Domain Service to have this issue) and you get the error:

Unable to update the EntitySet 'MyEntity' because it has a DefiningQuery and no <InsertFunction> element exists in the <ModificationFunctionMapping> element to support the current operation.

One common reason you get this is that the table you are trying to update doesn’t have a single primary key in the database. This then causes the Entity Framework to create a compound key of all the non-nullable columns.

To solve the issue, just create a primary key on the table and update your model. You will have to manually change the Entity Key property to False for all the properties that are not your primary key.

If you are not so lucky to have just forgot to create a primary on the database table, then you may check out this forum for more info on options. I was lucky, I just needed to add a primary key to my table. :) Good luck.

Thursday, March 18, 2010

How to determine if Navigation Property in the Entity Framework is set without loading the related record.

Boy that is a long title. There are times (particularly with a Domain Service) that you may want to just check if an Navigation Property has a related record or not. If you just check the Navigation Property for null then you can really mess things up because if you don’t explicitly load the related record, it will be null. It is often a waste to load the related record just to save, etc.

Luckily, there is an easy solution. In fact, it also provides you with the actual foreign key value (if there is one). This can be useful for other things. The Entity Framework removes foreign key properties from the Scalar Properties section of the entity. At first glance it appears that you no longer have access to the foreign key value.

The solution is quite simple. Let’s assume we have two entities. One is Department and it has a relationship (Navigation Property) called Manager that points to the Person entity. What I propose is we do the following to determine if the Manager Navigation Property on Department points to anything.

bool isMgr = myDept.ManagerReference.EntityKey != null;

That is it. So simple, but a little hidden. You can also get the actual key values if you access the properties on the EntityKey property.

Wednesday, March 10, 2010

RIA Services Rocks!

I cannot believe how cool RIA Services is. I knew it was cool, but I think it does everything I have been dreaming about.

Here is a video that shows how to do a pretty nice application in an hour. Simply AMAZING!!!

http://silverlight.net/learn/videos/all/net-ria-services-intro/

You can download RIA Services for Visual Studio 2008 or VS 2010 Beta. Click here for more info on downloading.

BTW, the entire sample in the video is in the Documentation / Samples of the download.

I’m sold!

Thursday, December 10, 2009

FieldValue in DynamicData ForeignKeyField is null, but it should not be

I am using ADO.NET Entity Framework and Dynamic Data in a ASP.NET Formview. It works great! Let’s pretend I am working with a Person entity. Then I added a Foreign key to my table (and EF Model) to another table called it Gender. I add the DynamicControl to my formview for the foreign key by setting the DataField to the name of the relationship from Person to Gener, in this case it is called Gender.

I added this to EditItemTemplate

<asp:DynamicControl ID="GenderDynamicControl" runat="server" DataField="Gender" Mode="Edit" ValidationGroup="Edit"  />

The two-way binding works great.

Then I go to the ItemTemplate and add

<asp:DynamicControl ID="GenderDynamicControl" runat="server" DataField="Gender" Mode="ReadOnly" ValidationGroup="ReadOnly"  />

I then test, and see that the ItemTemplate / Read only version of this doesn’t show any value. After debugging and looking at the FieldValue property in ForeignKey.ascx.cs I see that it is null when it should not be since the row I was looking at had a GenderID specified in the Person table.

Then I looked at the CRUD interface that you get for free when you create a Dynamic Data Web Site. It works great! That made no sense to me, but then I realized that the EntityDataSource I was using did NOT include the Gender entity, so this entity was not loaded. This is VERY characteristic of ADO.NET Entity Framework since it does lazy loading and requires that you specify what you want loaded. If you don’t, you don’t get the data.

So, the real solution was to just modify my EntityDataSource so that I include the Gender table as shown below. Some of the properties have been removed for simplicity in the code.

<asp:EntityDataSource ID="dsPerson" runat="server" 
EntitySetName="Person" 
Include="Gender">

Tuesday, November 24, 2009

Getting SqlConnection from EntityConnection

I love ADO.NET Entity Framework. The problem I ran into is I wanted to call a stored procedure, but I can’t really do that unless the stored procedure returns entity information, etc. I really just wanted to call a stored procedure, though it could have been embedded SQL also (if you do that sort of thing :), but I needed a SqlConnection to do that. All I had was a DbConnection which can be cast to and EntityConnection since I am using the EF. The question was how do I get to the SqlConnection that EF uses. Sure, I could have created another entry in my web.config or app.config and added another connection string. I don’t like to have some many connection strings though. A little looking around in the debugger and the solution became obvious.

Below is a simple method that takes my DbConnection and casts it to a EntityConnection. It then accesses the StoreConnection which returns a DbConnection and is cast to a SqlConnection. It then just gets the connection string from the SqlConnection,. From that point I can open a new connection of my own. Alternatively, I could have checked the state of that connection and opened and closed it appropriately. I didn’t want to worry about the state of the connection and messing up the EF, so I just create a new connection. Though both seem to work for my basic testing.

using System.Data.EntityClient;
using System.Data.SqlClient;
...
private string GetADOConnectionString()
{
SalesSyncEntities ctx = new SalesSyncEntities();
EntityConnection ec = (EntityConnection)ctx.Connection;
SqlConnection sc = (SqlConnection)ec.StoreConnection;
string adoConnStr = sc.ConnectionString;
return adoConnStr;
}

Thursday, November 12, 2009

Creating a Decimal Dynamic Data control that allows commas

I love the Dynamic Data architecture. I won’t get into how it all works, and assume you understand how to use the Decimal Dynamic Data control. For the most part, you never have to worry about it except maybe decorate your Entity with [UIHint (“Decimal”)].

Just open up your project that is a Dynamic Data project in Visual Studio 2008 and go to the DynamicData directory it created for you. Download the my two files (DecimalAllowingCommas_Edit.ascx.cs and DecimalAllowingCommas_edit.ascx) and put them in the FieldTemplates directory. Don’t forget to change your namespace and references to it.

The two files are slightly modified versions of the Decimal_Edit.ascx and Decimal_Edit.ascx.cs files that are already in that directory.

The difference is that I removed the CompareValidator and replaced it with a RegularExpressionValidator since the CompareValidator doesn’t allow for commas in the textfield, but my regular expression does. I also add a line in the Page_Load for this control that sets the ValidationGroup to the same as the other validators in that control. That gives us basically the same validation as we had before, but with commas allowed.

That handled the JavaScript validation and even server side validation, but when the values are automatically pushed to the properties on the entity which are of type double, .Net throws an exception that basically says it can’t convert the string to a double because it has commas in it. Seems a bit silly to me that it can’t do that, but we’ll fix that. I just removed the contents of the ExtractValues method and replaced them with my own that use the Decimal.TryParse() method to do the parsing. This method happily accepts the commas.

Now that we have support for our new type of Dynamic Data control, we need to use it. That is easy. In your entity where you had [UIHint(“Decimal”)], just replace that with [UIHint(“DecimalAllowingCommas”)]. Now when the UI renders editable version of that field it will use the DecimalAllowingCommas_Edit instead of the Decimal_Edit Dynamic Data Control.

On last thing, you will need make sure the ApplyFormatInEditMode property is set to true for the declaration of the DynamicControl in your parent control or page. Here is a the idea of what I am saying talking about.

<asp:FormView>
<EditItemTemplate>
<asp:DynamicControl
ID="CostPerYearDynamicControl" runat="server"
DataField="CostPerYear" Mode="Edit"
ValidationGroup="Edit"
ApplyFormatInEditMode="True"/>
</EditItemTemplate>
</asp:FormView>

 

Here is the source for the .ascx in case you don’t want to download the file.

<%@ Control Language="C#" CodeFile="DecimalAllowingCommas_Edit.ascx.cs" Inherits="MyApp.DecimalAllowingCommas_EditField" %>

<asp:TextBox ID="TextBox1" runat="server" CssClass="droplist" Text='<%# FieldValueEditString %>' Columns="10"></asp:TextBox>

<asp:RequiredFieldValidator runat="server" ID="RequiredFieldValidator1" CssClass="droplist" ControlToValidate="TextBox1" Display="Dynamic" Enabled="false" />
<asp:RegularExpressionValidator runat="server" ID="RegularExpressionValidator1" CssClass="droplist" ControlToValidate="TextBox1" Display="Dynamic" Enabled="false" />
<asp:RangeValidator runat="server" ID="RangeValidator1" CssClass="droplist" ControlToValidate="TextBox1" Type="Double"
Enabled="false" EnableClientScript="true" MinimumValue="0" MaximumValue="100" Display="Dynamic" />
<asp:DynamicValidator runat="server" ID="DynamicValidator1" CssClass="droplist" ControlToValidate="TextBox1" Display="Dynamic" />
<asp:RegularExpressionValidator ID="moneyRegexValidator" runat="server"
ControlToValidate="TextBox1" ErrorMessage="Must be of the format #,###.##."
ValidationExpression="^([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$"></asp:RegularExpressionValidator>

Here is the code for the .ascx.cs

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml.Linq;
using System.Web.DynamicData;

namespace MyApp
{
public partial class DecimalAllowingCommas_EditField : System.Web.DynamicData.FieldTemplateUserControl
{
protected void Page_Load(object sender, EventArgs e)
{
TextBox1.ToolTip = Column.Description;

SetUpValidator(RequiredFieldValidator1);
SetUpValidator(RegularExpressionValidator1);
SetUpValidator(RangeValidator1);
SetUpValidator(DynamicValidator1);

// copy it from one of the validators that knows what group we are in. :)
moneyRegexValidator.ValidationGroup = DynamicValidator1.ValidationGroup;

}

protected override void ExtractValues(IOrderedDictionary dictionary)
{
decimal result;
bool successful = Decimal.TryParse(TextBox1.Text, out result);
if (successful)
{
dictionary[Column.Name] = result;
}
}

public override Control DataControl
{
get
{
return TextBox1;
}
}
}
}