MVVM-Pattern for a Diagraming Application with WPF - Convert enum to xxxViewModel - mvvm

I'm trying to apply the MVVM design pattern to a diagramming application. In this application there are different items (for example a rectangle, a circle,...). I would like to save the item type as an enum in my model.
In my modelview I made a class for every item type (rectangleViewMode, circleViewMode,...).
On my view I apply a data template to the type, so it renders like a circle, or like a rectangle.
The problem is...how can I convert the enum in my model to the requiered xxxViewMode? I have a lot of types and I would like an automatic conversion.
I'm new to MVVM and maybe there is a better approach...so better solutions are welcome! :)
Thank you very much

I read your question a little differently to the other answerers, i don't believe you are just looking for a way to bind an enum to a combo, i think you are looking for a way to relate an enum value to an object type. If i got this wrong then stop reading now :)
First up: I'm not sure that saving the shape types as an enumeration (or even relating the shape to an enumeration) is very scalable. Read on, and i'll explain towards the end.
To relate an item type to an enum, just have the item return the appropriate enum value via a property:
public CircleViewMode
{
public ShapeType Shape { get { return ShapeType.Circle; }}
}
public enum ShapeType
{
Circle,
Square,
Rectangle,
Triangle,
FancyShape1,
FancyShape2
}
This means that you don't have to employ a converter or another translator mechanism. If you want to then populate a bunch of these into a combo then it is quite simple - check this following sample and insert breakpoints at the appropriate spot to see how it works.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
new Example().Run();
Console.ReadKey();
}
}
public class Example : INotifyPropertyChanged
{
public void Run()
{
var availableShapes = AllMyShapes.Where(x => x.NumberOfSides == 4);
AvailableShapes = new List<KeyValuePair<string, Type>>
(from Shape s in availableShapes
select new KeyValuePair<string, Type>(
Enum.GetName(typeof(ShapeType), s.ShapeType)
,s.GetType()
));
//at this point any combobox you have bound to the AvailableShapes property will now carry a new list of shapes
}
public List<Shape> AllMyShapes
{
get
{
return new List<Shape>() { new Circle(){NumberOfSides=1, ShapeType=ShapeType.Circle}
,new Square(){NumberOfSides=4, ShapeType=ShapeType.Square}
,new Rectangle(){NumberOfSides=4, ShapeType=ShapeType.Rectangle}
,new Triangle(){NumberOfSides=3, ShapeType=ShapeType.Triangle}
,new FancyShape1(){NumberOfSides=10, ShapeType=ShapeType.FancyShape1}
,new FancyShape2(){NumberOfSides=30, ShapeType=ShapeType.FancyShape2}
};
}
}
public List<KeyValuePair<string, Type>> AvailableShapes
{
get { return _availableShapes; }
protected set
{
_availableShapes = value;
}
}
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private List<KeyValuePair<string, Type>> _availableShapes;
public event PropertyChangedEventHandler PropertyChanged;
}
public abstract class Shape
{
public int NumberOfSides { get; set; }
public ShapeType ShapeType { get; set; }
}
public class Square : Shape { }
public class Rectangle : Shape { }
public class Triangle : Shape { }
public class Circle : Shape { }
public class FancyShape1 : Shape { }
public class FancyShape2 : Shape { }
public enum ShapeType
{
Circle,
Square,
Rectangle,
Triangle,
FancyShape1,
FancyShape2
}
}
With this approach you will have a combobox with nice human readable shape names in it, and you can instantly get the actual shape type of the selected item. It would be a trivial task to turn the class Example into an abstract base ViewModel, any ViewModel you then derive from it will have the AvailableShapes property.
But back to my original point of scalability - as you increase the shape types you also need to update the enumeration. This could be problematic if you ship libraries of new shapes or allow users to create their own. You may be better off saving it as myShape.GetType().ToString(), which returns a string value that can then be used to recreate the an instance of the object using reflection. In the above example of showing the items in a combo, you could just get a List<Type> of the available shapes and use a converter to produce a nice human readable name from the shape type (using a string resource file, eliminating the enumeration altogether).

Depending on your needs, you could use a converter class:
(stolen from How to bind RadioButtons to an enum?)
public class EnumBooleanConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string parameterString = parameter as string;
if (parameterString == null)
return DependencyProperty.UnsetValue;
if (Enum.IsDefined(value.GetType(), value) == false)
return DependencyProperty.UnsetValue;
object parameterValue = Enum.Parse(value.GetType(), parameterString);
return parameterValue.Equals(value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string parameterString = parameter as string;
if (parameterString == null)
return DependencyProperty.UnsetValue;
return Enum.Parse(targetType, parameterString);
}
#endregion
}

Related

Xamarin Forms Custom Bindable Command type mismatch

I've created a custom view called PINControl, which shows a PIN entry with a configurable amount of digits.
The XAML I'd like to use in my ContentPage is
<local:PINControl x:Name="PIN"
PINLength="5"
PINCompleteCommand="{Binding CompletePIN}"
HorizontalOptions="CenterAndExpand" />
My BindableProperties in the PINControl are:
public class PINControl : StackLayout
{
private const int LENGTH_DEFAULT = 4;
public static readonly BindableProperty PINLengthProp = BindableProperty.Create<PINControl, int> (c => c.PINLength, LENGTH_DEFAULT);
public static readonly BindableProperty PINCompleteCommandProp = BindableProperty.Create<PINControl, ICommand> (c => c.PINCompleteCommand, null);
public ICommand PINCompleteCommand {
get { return (ICommand)GetValue (PINCompleteCommandProp); }
set { SetValue (PINCompleteCommandProp, value); }
}
public int PINLength {
get { return (int)GetValue (PINLengthProp); }
set { SetValue (PINLengthProp, value); }
}
My ViewModel contains
public ICommand CompletePIN { get; set; }
public PINViewModel ()
{
CompletePIN = new Command<string> ((pin) => {
var e = pin.ToString();
});
}
It does not seem to have a problem with the PINLength, but the PINCompleteCommand is giving me the following error:
Cannot assign property "PINCompleteCommand": type mismatch between "Xamarin.Forms.Binding" and "System.Windows.Input.ICommand"
I cannot find a solution for this problem. Can somebody help me?
There is a good practice to follow while naming BindableProperties, which is to name it propertynameProperty.
In your case, when the Xaml parser encounter this instruction
PINCompleteCommand="{Binding CompletePIN}"
it first tries to find a public static BindableProperty with name PINCompleteCommandProperty, fails, then look for a normal property named PINCompleteCommand, succeed, and try to assign the value (a Binding) to the property (an ICommand) and generate the message you are seeing.
Fix your BindableProperty naming, and you should be fine.
Not sure it's applicable to the OP situation or not, but it's worth noting that this will also arise if the ViewModel/BindingTo property is the same name as the BindableProperty name and you bind the two together.
eg.
CustomControl
-> PinLengthCommand/PinLengthCommandProperty
ViewModel
-> PinLengthCommand
Just change the name of the property on the viewmodel and it will run OK.

Dynamic way to Generate EntityTypeConfiguration : The type 'TResult' must be a non-nullable value type

I was thinking to generate EntityTypeConfiguration dynamically from run time and i don't want any EF dependency in Models[That is why i avoid Data Annotation].
So I declare a custom attribute(or can be any configuration file later on)
[AttributeUsage(AttributeTargets.Property, AllowMultiple=true )]
public class PersistableMemberAttribute : Attribute
{
public bool Iskey;
public bool IsRequired;
public bool IsIgnored;
public bool IsMany;
public string HasForeignKey;
public bool PropertyIsRequired;
public bool PropertyIsOptional;
}
And here is one of my Models is look like:
public class Blog
{
[PersistableMember(Iskey=true)]
public Guid BlogId { get; set; }
[PersistableMember(PropertyIsRequired = true)]
public string Name { get; set; }
public string Url { get; set; }
[PersistableMember(IsIgnored=true)]
public int Rating { get; set; }
[PersistableMember(IsMany =true)]
public ICollection<Post> Posts { get; set; }
}
Now I am going to write a generic EntityTypeConfiguration , which will create the configuration dynamically on run time based on the attribute values :
public class GenericEntityConfiguration<T> : EntityTypeConfiguration<T> where T : class
{
public GenericEntityConfiguration()
{
var members = typeof(T).GetProperties();
if (null != members)
{
foreach (var property in members)
{
var attrb= property.GetCustomAttributes(typeof( PersistableMemberAttribute ),false).OfType<PersistableMemberAttribute>();
if (attrb != null && attrb.Count() > 0)
{
foreach (var memberAttributute in attrb)
{
if (memberAttributute.Iskey || memberAttributute.IsIgnored)
{
var entityMethod = this.GetType().GetMethod("Setkey");
entityMethod.MakeGenericMethod(property.PropertyType)
.Invoke(this, new object[] { property, memberAttributute });
}
if (memberAttributute.IsRequired)
{
var entityMethod = this.GetType().GetMethod("SetRequired");
entityMethod.MakeGenericMethod(property.PropertyType)
.Invoke(this, new object[] { property, memberAttributute });
}
if (memberAttributute.PropertyIsRequired || memberAttributute.PropertyIsOptional)
{
var entityMethod = this.GetType().GetMethod("SetPropertyConfiguration");
entityMethod.MakeGenericMethod(property.PropertyType)
.Invoke(this, new object[] { property, memberAttributute });
}
}
}
}
}
}
public void SetPropertyConfiguration<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute)
{
var functorParam = Expression.Parameter(typeof(T));
var lambda = Expression.Lambda(
Expression.Property(functorParam, propertyInfo)
, functorParam);
if (attribute.PropertyIsRequired)
{
this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsRequired();
}
if (attribute.PropertyIsOptional)
{
this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsOptional();
}
}
public void Setkey<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute)
{
var functorParam = Expression.Parameter(typeof(T));
var lambda = Expression.Lambda(
Expression.Property(functorParam, propertyInfo)
, functorParam);
if (attribute.Iskey)
{
this.HasKey<TResult>((Expression<Func<T,TResult>>)lambda);
}
if (attribute.IsIgnored)
{
this.Ignore<TResult>((Expression<Func<T, TResult>>)lambda);
}
}
public void SetRequired<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute) where TResult : class
{
var functorParam = Expression.Parameter(typeof(T));
var lambda = Expression.Lambda(
Expression.Property(functorParam, propertyInfo)
, functorParam);
if (attribute.IsRequired)
{
this.HasRequired<TResult>((Expression<Func<T, TResult>>)lambda);
}
}
}
But i got the compilation error of
Error 1 The type 'TResult' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Data.Entity.ModelConfiguration.Configuration.StructuralTypeConfiguration.Property(System.Linq.Expressions.Expression>)' D:\R&D\UpdateStorePOC\UpdateStorePOC\Data\GenericEntityConfiguration.cs 63 17 UpdateStorePOC
which for these two statements:
this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsRequired();
this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsOptional();
that means that I need to put a constraint on my method to restrict it to a value type. In C#, this is done with the ‘struct’ keyword.
public void SetPropertyConfiguration<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute) Where TResult : struct
But Its not the solution since my property type can be a class e.g string or int, bool double, etc . So it is not at all clear that I can send them into this method. Please help me to solve this issue whether there is any other way to do it.
I don't want any EF dependency in models.
With fluent mapping you're almost there and you won't come any closer. Your attributes, even though intended to be moved to a configuration file, don't make your model any more free of any EF footprint.1 Worse, they only add a second mapping layer (if you like) between your model and EF's mapping. I only see drawbacks:
You still have to maintain meta data for your model, probably not any less than regular fluent mapping and (probably) in awkward manually edited XML without compile-time checking.
You will keep expanding your code to cover cases that EF's mapping covers but yours doesn't yet.2 So it's a waste of energy: in the end you'll basically have rewritten EF's mapping methods.
You'll have to keep your fingers crossed when you want to upgrade EF.
With bugs/problems you're on your own: hard to get support from the community.
So my answer to your question help me to solve this issue would be: use fluent mapping out of the box. Keep it simple.
1 For example, you would still have to use the virtual modifier to enable proxies for lazy loading.
2 Like support for inheritance, unmapped foreign keys, max length, db data type, ... this could go on for a while.

PostSharp aspect call only once per instance

I use PostSharp aspect below to validate Property of the class.
[ProtoContract]
public sealed class Web2Image : WebEntity
{
[ProtoMember(1009), Validator.Collection(Data = new[] { "jpg", "bmp", "png", "tiff" })]
public override string OutputFormat { get; set; }
}
The property OutputFormat is validated on first property access but Validation is executed and second and third time when property accessed in the code.
I would like to limit Aspect execution only once per class instance for my property. How to do that?
public class Validator
{
[Serializable]
[Collection(AttributeExclude = true)]
[MulticastAttributeUsage(MulticastTargets.Property)]
public class Collection : LocationInterceptionAspect
{
public string[] Data;
public override void OnGetValue(LocationInterceptionArgs args)
{
SiAuto.Main.LogObject("FieldAccessEventArgs " + Reflection.AssemblyHelper.EntryAssembly, args);
/* SiAuto.Main.LogObject("FieldAccessEventArgs " + Reflection.AssemblyHelper.EntryAssembly, args.Binding.ToString());*/
args.ProceedGetValue();
if (args.Value == null)
{
args.Value = Data[0];
args.ProceedSetValue();
}
foreach (var s in Data)
{
if (args.Value.ToString().ToLower() == s.ToLower())
return;
}
throw new EngineException(string.Format("Value \"{0}\" is not correct. {1} parameter can accept only these values {2}", args.Value, args.LocationName, string.Join(",", Data)));
}
}
}
You will need to implement IInstanceScopedAspect. See http://www.sharpcrafters.com/blog/post/Day-9-Aspect-Lifetime-Scope-Part-1.aspx and http://www.sharpcrafters.com/blog/post/Day-10-Aspect-Lifetime-Scope-Part-2.aspx for more about the lifetime and scope of aspects including how to implement IInstanceScopedAspect.
That will get you the per instance aspect (because right now it's once per type).
As far as the checking, you can set a switch (if true, exit otherwise, do check) or check if it's null (or some other initial value).

ObservableCollection of generic ViewModel class

I'm creating MVVM application and in Model section I have simple base abstract class Animal and class Dog which derives from it:
public abstract class Animal
{
public int Age { get; set; }
}
public class Dog : Animal
{
public string Name { get; set; }
}
ViewModel section containts UI-friendly VM classes of them:
public abstract class AnimalVM<T> : ViewModelBase where T : Animal
{
protected readonly T animal;
public int Age
{
get { return animal.Age; }
set
{
animal.Age = value;
OnPropertyChanged("Age");
}
}
protected AnimalVM(T animal)
{
this.animal = animal;
}
}
public class DogVM : AnimalVM<Dog>
{
public string Name
{
get { return animal.Name; }
set
{
animal.Name = value;
OnPropertyChanged("Name");
}
}
public DogVM(Dog dog) : base(dog) { }
}
Suppose I have another VM class which contains ObservableCollection<AnimalVM>. The problem is how to create that kind of property which allow me to store there different types of Animal? I want to achieve something like this:
public class AnimalListVM : ViewModelBase
{
// here is a problem, because AnimalVM<Animal> isn't compatible with DogVM
readonly ObservableCollection<AnimalVM<Animal>> animals;
public ObservableCollection<AnimalVM<Animal>> Animals
{
get { return animals; }
}
public AnimalListVM(IList<Animal> animals)
{
//this.animals = ...
}
}
I can change ObservableCollection<AnimalVM<Animal>> property to ICollection property and then create list of AnimalVM using some dictionary Animal -> AnimalVM wrapper and Activator.CreateInstance() - it works but when I try to extend AnimalListVM adding another property SelectedAnimal which will be binded in sample View to e.g. DataGrid control I have another problem with type of that kind of property SelectedItem. It can't be of type AnimalVM<Animal> because when I have DogVM object in my Collection it won't fit with this and throw an exception.
Everything will be clear if only I had non-generic AnimalVM but I don't want to copy and paste similar properties in every DogVM, CatVM, BirdVM class derived from AnimalVM. How can I achieve this?
Ok, I've found a solution and of course it's very simple: just create another, non-generic abstract base class for your generic abstract base class and then derive your generic class from that newly created non-generic class. In that case you also must rewrite properties from non-generic class to generic class (to be more specific override them), but you do this only once, so you don't have to copy and paste the same code in every generic derived ViewModel (in our example in every DogVM, CatVM, BirdVM, etc.).

Can I hide my ICollection<T> fields when I have a one-to-many mapping in EF4 code-only?

My domain classes that have one-to-many mappings generally take the following form (untested code):
public Customer Customer
{
// Public methods.
public Order AddOrder(Order order)
{
_orders.Add(order);
}
public Order GetOrder(long id)
{
return _orders.Where(x => x.Id).Single();
}
// etc.
// Private fields.
private ICollection<Order> _orders = new List<Order>();
}
The EF4 code-only samples I've seen expose a public ICollection when dealing with one-to-many relationships.
Is there a way to persist and restore my collections with exposing them? If not, it would appear that my domain objects will be designed to meet the requirements of the ORM, which seems to go against the spirit of the endeavour. Exposing an ICollection (with it's Add, etc. methods) doesn't seem particularly clean, and wouldn't be my default approach.
Update
Found this post that suggests it wasn't possible in May. Of course, the Microsoft poster did say that they were "strongly considering implementing" it (I'd hope so) and we're half a year on, so maybe there's been some progress?
I found that whatever was done, EF requires the ICollection<T> to be public. I think this is because when the objects are loaded from the database, the mapping looks for a collection property, gets the collection and then calls the Add method of the collection to add each of the child objects.
I wanted to ensure that the addition was done through a method on the parent object so created a solution of wrapping the collection, catching the add and directing it to my preferred method of addition.
Extending a List and other collection types was not possible because the Add method is not virtual. One option is to extend Collection class and override the InsertItem method.
I have only focussed on the Add, Remove, and Clear functions of the ICollection<T> interface as those are the ones that can modify the collection.
First, is my base collection wrapper which implements the ICollection<T> interface
The default behaviour is that of a normal collection. However, the caller can specify an alternative Add method to be called. In addition, the caller can enforce that the Add, Remove, Clear operations are not permitted by setting the alternatives to null. This results in NotSupportedException being thrown if anyone tries to use the method.
The throwing of an exception is not as good as preventing access in the first place. However, code should be tested (unit tested) and an exception will be found very quickly and a suitable code change made.
public abstract class WrappedCollectionBase<T> : ICollection<T>
{
private ICollection<T> InnerCollection { get { return GetWrappedCollection(); } }
private Action<T> addItemFunction;
private Func<T, bool> removeItemFunction;
private Action clearFunction;
/// <summary>
/// Default behaviour is to be like a normal collection
/// </summary>
public WrappedCollectionBase()
{
this.addItemFunction = this.AddToInnerCollection;
this.removeItemFunction = this.RemoveFromInnerCollection;
this.clearFunction = this.ClearInnerCollection;
}
public WrappedCollectionBase(Action<T> addItemFunction, Func<T, bool> removeItemFunction, Action clearFunction) : this()
{
this.addItemFunction = addItemFunction;
this.removeItemFunction = removeItemFunction;
this.clearFunction = clearFunction;
}
protected abstract ICollection<T> GetWrappedCollection();
public void Add(T item)
{
if (this.addItemFunction != null)
{
this.addItemFunction(item);
}
else
{
throw new NotSupportedException("Direct addition to this collection is not permitted");
}
}
public void AddToInnerCollection(T item)
{
this.InnerCollection.Add(item);
}
public bool Remove(T item)
{
if (removeItemFunction != null)
{
return removeItemFunction(item);
}
else
{
throw new NotSupportedException("Direct removal from this collection is not permitted");
}
}
public bool RemoveFromInnerCollection(T item)
{
return this.InnerCollection.Remove(item);
}
public void Clear()
{
if (this.clearFunction != null)
{
this.clearFunction();
}
else
{
throw new NotSupportedException("Clearing of this collection is not permitted");
}
}
public void ClearInnerCollection()
{
this.InnerCollection.Clear();
}
public bool Contains(T item)
{
return InnerCollection.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
InnerCollection.CopyTo(array, arrayIndex);
}
public int Count
{
get { return InnerCollection.Count; }
}
public bool IsReadOnly
{
get { return ((ICollection<T>)this.InnerCollection).IsReadOnly; }
}
public IEnumerator<T> GetEnumerator()
{
return InnerCollection.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return InnerCollection.GetEnumerator();
}
}
Given that base class we can use it in two ways. Examples are using the original post objects.
1) Create a specific type of wrapped collection (For example, List)
public class WrappedListCollection : WrappedCollectionBase, IList
{
private List innerList;
public WrappedListCollection(Action<T> addItemFunction, Func<T, bool> removeItemFunction, Action clearFunction)
: base(addItemFunction, removeItemFunction, clearFunction)
{
this.innerList = new List<T>();
}
protected override ICollection<T> GetWrappedCollection()
{
return this.innerList;
}
<...snip....> // fill in implementation of IList if important or don't implement IList
}
This can then be used:
public Customer Customer
{
public ICollection<Order> Orders {get { return _orders; } }
// Public methods.
public void AddOrder(Order order)
{
_orders.AddToInnerCollection(order);
}
// Private fields.
private WrappedListCollection<Order> _orders = new WrappedListCollection<Order>(this.AddOrder, null, null);
}
2) Give a collection to be wrapped using
public class WrappedCollection<T> : WrappedCollectionBase<T>
{
private ICollection<T> wrappedCollection;
public WrappedCollection(ICollection<T> collectionToWrap, Action<T> addItemFunction, Func<T, bool> removeItemFunction, Action clearFunction)
: base(addItemFunction, removeItemFunction, clearFunction)
{
this.wrappedCollection = collectionToWrap;
}
protected override ICollection<T> GetWrappedCollection()
{
return this.wrappedCollection;
}
}
which can be used as follows:
{
public ICollection Orders {get { return _wrappedOrders; } }
// Public methods.
public void AddOrder(Order order)
{
_orders.Add(order);
}
// Private fields.
private ICollection<Order> _orders = new List<Order>();
private WrappedCollection<Order> _wrappedOrders = new WrappedCollection<Order>(_orders, this.AddOrder, null, null);
}
There are some other ways to call the WrappedCollection constructors
For example, to override add but keep remove and clear as normal
private WrappedListCollection<Order> _orders = new WrappedListCollection(this.AddOrder, (Order o) => _orders.RemoveFromInnerCollection(o), () => _orders.ClearInnerCollection());
I agree that it would be best if EF would not require the collection to be public but this solution allows me to control the modification of my collection.
For the problem of preventing access to the collection for querying you can use approach 2) above and set the WrappedCollection GetEnumerator method to throw a NotSupportedException. Then your GetOrder method can stay as it is. A neater method however may be to expose the wrapped collection. For example:
public class WrappedCollection<T> : WrappedCollectionBase<T>
{
public ICollection<T> InnerCollection { get; private set; }
public WrappedCollection(ICollection<T> collectionToWrap, Action<T> addItemFunction, Func<T, bool> removeItemFunction, Action clearFunction)
: base(addItemFunction, removeItemFunction, clearFunction)
{
this.InnerCollection = collectionToWrap;
}
protected override ICollection<T> GetWrappedCollection()
{
return this.InnerCollection;
}
}
Then the call in the GetOrder method would become
_orders.InnerCollection.Where(x => x.Id == id).Single();
Another way to accomplish this would be to create an associated interface for each of your POCOs to expose only what you want outside of the persistence/domain layers. You can also interface your DbContext class to also hide and control access to the DbSet collections. As it turns out, the DbSet properties can be protected, and the model builder will pick them up when it's creating tables, but when you try to access the collections they will be null. A factory method (in my example, CreateNewContext) can be used instead of the constructor to get the interfaced DbContext to conceal the DbSet collections.
There's quite a bit of extra effort in coding, but if hiding implementation details within the POCOs is important, this will work.
UPDATE: It turns out you CAN populate DBSets if they are protected, but not directly in the DBContext. They can't be aggregate roots (i.e. accessibility of the entity has to be through a collection in one of the public DBSet entities). If hiding the implementation of DBSet is important, the interface pattern I've described is still relevant.
public interface ICustomer
{
void AddOrder(IOrder order);
IOrder GetOrder(long id);
}
public Customer : ICustomer
{
// Exposed methods:
void ICustomer.AddOrder(IOrder order)
{
if (order is Order)
orders.Add((Order)order);
else
throw new Exception("Hey! Not a mapped type!");
}
IOrder ICustomer.GetOrder(long id)
{
return orders.Where(x => x.Id).Single();
}
// public collection for EF
// The Order class definition would follow the same interface pattern illustrated
// here for the Customer class.
public ICollection<Order> orders = new List<Order>();
}
public interface IMyContext
{
IEnumerable<ICustomer> GetCustomers();
void AddCustomer(ICustomer customerObject);
ICustomer CreateNewCustomer()
}
public class MyContext : DbContext, IMyContext
{
public static IMyContext CreateNewContext() { return new MyContext(); }
public DbSet<Customer> Customers {get;set;}
public DbSet<Order> Orders {get;set;}
public IEnumerable<ICustomer> GetCustomers()
{
return Customers;
}
public void AddCustomer(ICustomer customerObject)
{
if (customerObject is Customer)
Customers.Add((Customer)customerObject);
else
throw new Exception("Hey! Not a mapped type");
}
public ICustomer CreateNewCustomer()
{
return Customers.Create();
}
// wrap the Removes, Finds, etc as necessary. Remember to add these to the
// DbContext's interface
// Follow this pattern also for Order/IOrder
}
If you change the name of your _orders collection to the name of the orders table in your database, this should work. EF maps table/field names to collections/properties by convention. If you want to use a different name you could edit the mappings in the edmx file.
AFAIK you can just leave the private modifier as it is. Collections do not need to be public.