Binding EF4 with Caliburn.Micro: Should I expose my Entity as a property of the ViewModel?
Asked Answered
G

2

5

With Caliburn.Micro I'd like to know the pros and cons of exposing an EF4 Entity as a property of the ViewModel (a technique discussed here and here). This allows me to avoid writing getters and setters for every field (see OneCustomer below). The drawback is I need to write all of the binding statements in XAML (below LastName is not in the ViewModel but does require XAML binding). If I stick to the prescribed technique of filling my ViewModel with properties for each field (as FirstName below) I'll ultimately have to write a ton of extra code just so NotifyOfProperyChange will get called. The application will be quite large. Should I expose each entity as a property of the ViewModel?

In My ViewModel:

private MyEntities _context = new MyEntities();
private BindableCollection<Customer> _custBindableCollection; 
private Customer _oneCustomer;
private string _firstName;

public void Load() 
{
    _custBindableCollection = new BindableCollection<Customer>(_context.Customers.Where(row => row.CustomerType == "FOO"));
    AllCustomers = _custBindableCollection;
    _oneCustomer = _custBindableCollection.FirstOrDefault();
    FirstName = _oneCustomer.FirstName;
    OneCustomer = _oneCustomer;
}

public BindableCollection<Customer> AllCustomers
{ 
get { return _custBindableCollection;}
set {_custBindableCollection = value;
      NotifyOfPropertyChange(() => AllCustomers);}
}

public Customer OneCustomer
{
 get { return _oneCustomer;}
 set { _oneCustomer = value;
        NotifyOfPropertyChange(() => OneCustomer);}
} 

public string FirstName
{
    get { return _firstName; }
    set {
        _firstName = value;
        _oneCustomer.FirstName = value;
        NotifyOfPropertyChange(() => FirstName);
        NotifyOfPropertyChange(() => CanSaveChanges);
    }
}

public void SaveChanges()
{ _context.SaveChanges(); }

public bool CanSaveChanges { get { return IsValid; } }

In My View:

<StackPanel>
<StackPanel Orientation="Horizontal">
    <Label Content="First Name:" />
    <TextBox x:Name="FirstName" />
</StackPanel>
<StackPanel Orientation="Horizontal" DataContext="{Binding Path=OneCustomer}">
    <Label Content="Last Name:" />
    <TextBox x:Name="LastName" Text="{Binding LastName}" />
</StackPanel>
<Button Content="Load Data" x:Name="Load" />
<Button Content="Save" x:Name="SaveChanges"  />
<DataGrid x:Name="AllCustomers" />

Thanks in advance.

Geodetic answered 14/9, 2011 at 21:0 Comment(0)
M
5

With Caliburn.Micro I'd like to know the pros and cons of exposing an EF4 Entity as a property of the ViewModel (a technique discussed here and here).

I'm not sure of the pros/cons but I can tell you both methods are used. For example take a simple Login Screen, generally I put the UserName a property on the ViewModel but in cases where the form is more complex the ViewModel can aggregate other ViewModels(display models) to accomplish the same thing. CM doesn't effect the pros/cons much as its more a question of With MVVM, what are the pros/cons. CM is going to help you in binding to both.

  • If you have a property on the ViewModel called CustomerName, simply name a TextBox x:name="CustomerName".
  • If you have a property on the ViewModel that is a instance of a class called Customer, name the TextBox x:name="Customer_Name" and again, CM will handle the bindings.

So from your xaml above:

 <TextBox x:Name="LastName" Text="{Binding LastName}" />

you don't need to set the DataContext on the StackPanel. Instead:

<TextBox x:Name="OneCustomer_LastName"/>

One thing that can make binding to DataForms and DataGrids easier is following a method where you create display models for the way the data is represented on the screen.

This is my opinion but I personally will never bind directly to an EF/Linq entity. Instead I'll create a display model to represent that entity and how I want it displayed and use AutoMapper to do the mappings. In a lot of cases its a one to one mapping. This might seem like a waste of time but it has advantages especially with more complex data model layouts, display models allow you to flatten the data for display purposes and attribute up properties for validation without sticking them on the data model entity. For more on that check out the chapter on it in ASP.NET MVC in Action book.

Monadelphous answered 15/9, 2011 at 15:36 Comment(5)
This is great information. Especially the CM convention of interpreting an underscore as dot notation. I will definitely check out AutoMapper and the MVC book. One small question though...should entity properties be updated in the setters (to value), or should I wait until save is clicked and update all at once? Thanks again.Geodetic
Are you asking when to persist to the database, when a properties value changes vs. the user clicking save?Monadelphous
No, I'll persist on save (chunky not chatty rule). What I was thinking is if I don't expose the entity, I could wait until Save to update all of the entity properties. But now that I think about it that doesn't make sense because I'd have to update all values even if only one was changed. So, I've answered my own question - I'll keep entity property/field updates in the setters.Geodetic
@DerekBeattie ..I know this is an old question, but I'm learning this now too and I have a question regarding your suggestion to use display models, and then use AutoMapper to map from your EF Entities to the Display Models. I would think that by using this approach you'd be losing the advantage of Two-Way databinding between the view, say a TextBox.Text property and the property on the model. If the user types in the text box, I want the data to update on the model automatically. Wouldn't Automapper get in the way?Oribella
Through an ajax call or something? This answer is probably dated a bit.Monadelphous
S
3

Since there are other advantages of exposing entities (for example, validation through attributes), I personally do expose them directly.

But I guess the proper answer would be "it depends" as there are always some drawbacks too (mainly architectural).

BTW: you can call the textbox "OneCustomer_LastName" and C.M's convention binding will work.

Selfregard answered 15/9, 2011 at 15:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.