i am Trying to fit in breezeJS with my existing architecture. I have a structure like
html/JS/Angular :: based view using hot-towel angular.
web api controllers :: whom the view calls.
Services layer :: that is being called from Web api. Any business logic goes here.
Unit of Work :: And (if) business logic requires to talk to data base for CRUDs it calls UOW.
Repository Pattern :: UOW is actually wrapping repositories. and repositores in turn talking to DbContexts.
Uptill now i was able to conver normal repositories implementation into the one using
public EFContextProvider<MyContext> DbContext { get; set; }
instead of just DbContext and i am also exposing MetaData using a string property with in UOW and IQueryables are returned using DbContext.Context.SomeEntity
Question 1 : Am i on right track ??
Question 2 : Most of the breeze examples are suggesting one SaveChanges method that give you all the entities that were changed and it will persist it at once. What if i want to trigger some business logic before Add,Update and Delete. i want to call me AddSomething service method and want to have a particular type of entity being sent to AddSomething and run some business logic before persistence. How can i put it together.
my code looksl ike
[BreezeController]//This is the controller
public class BreezeController : ApiController
{
private readonly ISomeService someService;
public BreezeController(ISomeService someService)
{
this.someService = someService;
}
// ~/breeze/todos/Metadata
[HttpGet]
public string Metadata()
{
return someService.MetaData();
}
// ~/breeze/todos/Todos
// ~/breeze/todos/Todos?$filter=IsArchived eq false&$orderby=CreatedAt
[HttpGet]
public IQueryable<Node> Nodes()
{
return nodesService.GetAllNodes().AsQueryable();
}
// ~/breeze/todos/SaveChanges
//[HttpPost]
//public SaveResult SaveChanges(JObject saveBundle)
//{
// return _contextProvider.SaveChanges(saveBundle);
//}
Below is the service
public class SomeService : BaseService, ISomeService
{
private readonly IUow Uow;
public SomeService(IUow Uow)
: base(Uow)
{
this.Uow = Uow;
}
public IEnumerable<Something> GetAllNodes()
{
return Uow.Somethings.GetAll();
}
}
every service can expose one property through base. that is actually the meta data
public class BaseService : IBaseService
{
private readonly IUow Uow;
public BaseService(IUow Uow)
{
this.Uow = Uow;
}
public string MetaData()
{
return Uow.MetaData;
}
}
and the my UOW looks like
public class VNUow : IUow, IDisposable
{
public VNUow(IRepositoryProvider repositoryProvider)
{
CreateDbContext();
repositoryProvider.DbContext = DbContext;
RepositoryProvider = repositoryProvider;
}
// Code Camper repositories
public IRepository<Something> NodeGroup { get { return GetStandardRepo<Something>(); } }
} }
public IRepository<Node> Nodes { get { return GetStandardRepo<Node>(); } }
/// <summary>
/// Save pending changes to the database
/// </summary>
public void Commit()
{
//System.Diagnostics.Debug.WriteLine("Committed");
DbContext.Context.SaveChanges();
}
public string MetaData // the Name property
{
get
{
return DbContext.Metadata();
}
}
protected void CreateDbContext()
{
// DbContext = new VNContext();
DbContext = new EFContextProvider<VNContext>();
// Load navigation properties always if it is true
DbContext.Context.Configuration.LazyLoadingEnabled = false;
// Do NOT enable proxied entities, else serialization fails
DbContext.Context.Configuration.ProxyCreationEnabled = true;
// Because Web API will perform validation, we don't need/want EF to do so
DbContext.Context.Configuration.ValidateOnSaveEnabled = false;
//DbContext.Configuration.AutoDetectChangesEnabled = false;
// We won't use this performance tweak because we don't need
// the extra performance and, when autodetect is false,
// we'd have to be careful. We're not being that careful.
}
protected IRepositoryProvider RepositoryProvider { get; set; }
private IRepository<T> GetStandardRepo<T>() where T : class
{
return RepositoryProvider.GetRepositoryForEntityType<T>();
}
private T GetRepo<T>() where T : class
{
return RepositoryProvider.GetRepository<T>();
}
private EFContextProvider<VNContext> DbContext { get; set; }
#region IDisposable
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (DbContext != null)
{
DbContext.Context.Dispose();
}
}
}
#endregion
}
in the end Repository Implementaion looks like
public class EFRepository<T> : IRepository<T> where T : class
{
public EFRepository(EFContextProvider<VNContext> dbContext)
{
if (dbContext == null)
throw new ArgumentNullException("dbContext");
DbContext = dbContext;
DbSet = DbContext.Context.Set<T>();
}
protected EFContextProvider<VNContext> DbContext { get; set; }
protected DbSet<T> DbSet { get; set; }
public virtual IQueryable<T> GetAll()
{
return DbSet;
}
public virtual IQueryable<T> GetAllEagerLoad(params Expression<Func<T, object>>[] children)
{
children.ToList().ForEach(x => DbSet.Include(x).Load());
return DbSet;
}
public virtual IQueryable<T> GetAllEagerLoadSelective(string[] children)
{
foreach (var item in children)
{
DbSet.Include(item);
}
return DbSet;
}
public virtual IQueryable<T> GetAllLazyLoad()
{
return DbSet;
}
public virtual T GetById(int id)
{
//return DbSet.FirstOrDefault(PredicateBuilder.GetByIdPredicate<T>(id));
return DbSet.Find(id);
}
public virtual T GetByIdLazyLoad(int id, params Expression<Func<T, object>>[] children)
{
children.ToList().ForEach(x => DbSet.Include(x).Load());
return DbSet.Find(id);
}
public virtual void Add(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Context.Entry(entity);
if (dbEntityEntry.State != EntityState.Detached)
{
dbEntityEntry.State = EntityState.Added;
}
else
{
DbSet.Add(entity);
}
}
public virtual void Update(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Context.Entry(entity);
if (dbEntityEntry.State == EntityState.Detached)
{
DbSet.Attach(entity);
}
dbEntityEntry.State = EntityState.Modified;
}
public virtual void Delete(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Context.Entry(entity);
if (dbEntityEntry.State != EntityState.Deleted)
{
dbEntityEntry.State = EntityState.Deleted;
}
else
{
DbSet.Attach(entity);
DbSet.Remove(entity);
}
}
public virtual void Delete(int id)
{
var entity = GetById(id);
if (entity == null) return; // not found; assume already deleted.
Delete(entity);
}
}
Much of this question is broad question and answers will be primarily opinion based... that said, here's my two cents: keep it simple. Carefully consider whether you truly need 3, 4 and 5, especially whether you need to implement UoW or the Repository Pattern yourself. The EF DbContext implements both, you could use it in your controllers directly if you wanted.
If you have custom logic that needs to execute prior to savechanges utilize one of the interceptor methods: BeforeSaveEntity or BeforeSaveEntites. Here's the documentation for those methods:
http://www.getbreezenow.com/documentation/contextprovider#BeforeSaveEntity
Breeze supports "Named saves" where you specify the name of the specific server endpoint ( i.e. your service method) on a per save basis. See:
http://www.getbreezenow.com/documentation/saving-changes
This would look something like this on your client.
var saveOptions = new SaveOptions({ resourceName: "CustomSave1" });
em.saveChanges(entitiesToSave, saveOptions).then(function (saveResult) {
// .. do something interesting.
}
and on your server
[HttpPost]
public SaveResult CustomSave1(JObject saveBundle) {
ContextProvider.BeforeSaveEntityDelegate = CustomSave1Interceptor;
return ContextProvider.SaveChanges(saveBundle);
}
private Dictionary<Type, List<EntityInfo>> CustomSave1Interceptor(Dictionary<Type, List<EntityInfo>> saveMap) {
// In this method you can
// 1) validate entities in the saveMap and optionally throw an exception
// 2) update any of the entities in the saveMap
// 3) add new entities to the saveMap
// 4) delete entities from the save map.
// For example
List<EntityInfo> fooInfos;
if (!saveMap.TryGetValue(typeof(Foo), out fooEntities)) {
// modify or delete any of the fooEntites
// or add new entityInfo instances to the fooEntities list.
}
}
Related
I have been trying to use DI within my Unit of Work / Repository pattern in WPF. The problem I am running into currently is if I make a call to a repository like _UserRepo.Add(User) and an exception is thrown. Every new call to the repository throws the exception because the context is never disposed of.
What I have tried
Unit Of Work
public class UnitOfWork : IUnitOfWork
{
private DbContextTransaction _trans;
private BomConfiguratorContext _context;
public UnitOfWork(BomConfiguratorContext context)
{
_context = context;
_trans = context.Database.BeginTransaction();
}
public void Dispose()
{
try
{
_context.SaveChanges();
_trans.Commit();
}
catch (Exception)
{
_trans.Rollback();
}
finally
{
_context.Dispose(); //This obviously does not work
}
}
}
Unit Of Work Factory
public class UnitOfWorkFactory : IUnitOfWorkFactory
{
private BomConfiguratorContext _context;
public UnitOfWorkFactory(BomConfiguratorContext context)
{
_context = context;
}
public UnitOfWork Create()
{
return new UnitOfWork(_context);
}
}
My Generic Repository
public interface IRepository<TEntity> where TEntity : class
{
void Add(TEntity entity);
void AddRange(IEnumerable<TEntity> entities);
void Remove(TEntity entity);
void RemoveRange(IEnumerable<TEntity> entities);
TEntity Get(int id);
IEnumerable<TEntity> GetAll();
IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate);
void Update(TEntity entity);
}
Generic Repository Implementation
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected readonly BomConfiguratorContext Context;
public Repository(BomConfiguratorContext context)
{
Context = context;
}
public virtual void Add(TEntity entity)
{
Context.Set<TEntity>().Add(entity);
}
public void AddRange(IEnumerable<TEntity> entities)
{
Context.Set<TEntity>().AddRange(entities);
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return Context.Set<TEntity>().Where(predicate);
}
public TEntity Get(int id)
{
return Context.Set<TEntity>().Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return Context.Set<TEntity>().ToList();
}
public void Remove(TEntity entity)
{
Context.Set<TEntity>().Remove(entity);
}
public void RemoveRange(IEnumerable<TEntity> entities)
{
Context.Set<TEntity>().RemoveRange(entities);
}
public void Update(TEntity entity)
{
Context.Set<TEntity>().Attach(entity);
Context.Entry(entity).State = System.Data.Entity.EntityState.Modified;
}
}
User Repository
public class UserRepository : Repository<User>,IUserRepository
{
public UserRepository(BomConfiguratorContext context)
:base(context)
{
}
}
Use Case
using (var UOW = _UnitOfWorkFactory.Create())
{
//Submit the user
_UserRepository.Add(ExampleNewUser);
}
So currently I am using MVVM Light to do all my DI work, now I understand with mvvm light you can only inject with singleton scope. So I am pretty sure I will end up having to switch over to something like Ninject so I can utilize their .InTransientScope or .InNamedScope (from what I have been reading).
Obviously the above code will not work with MVVM Light since the context is never properly disposed of.
The Question
So my question to you is if I were to swap over to using Ninject and start injecting my Context into these repositories / unit of work. How do I properly configure it to AWLAYS inject a new context within my unit of work for the repositories.
I read that Ninject MVC has .InRequestScope which would solve the issue entirely. But what about for WPF? How do you achieve the same kind of injection?
I can't seem to find the exact solution/pattern or maybe there is a better way to do this? Any suggestions and help would be greatly appreciated.
My solution to the problem was to create a ContextFactory.
Interface
public interface IContextFactory
{
BomConfiguratorContext Create();
BomConfiguratorContext Get();
}
Context Factory
The Factory allows me to either Get an existing context or create a new context.
public class ContextFactory : IContextFactory
{
private BomConfiguratorContext _context;
public ContextFactory(BomConfiguratorContext context)
{
_context = context;
}
public BomConfiguratorContext Create()
{
_context = new BomConfiguratorContext();
return _context;
}
public BomConfiguratorContext Get()
{
return _context;
}
}
New Base Repository
By calling the ContextFactory.Get() method I use the cached context instead of creating a new one.
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected readonly IContextFactory ContextFactory;
public Repository(IContextFactory factory)
{
ContextFactory = factory;
}
public virtual void Add(TEntity entity)
{
ContextFactory.Get().Set<TEntity>().Add(entity);
}
public void AddRange(IEnumerable<TEntity> entities)
{
ContextFactory.Get().Set<TEntity>().AddRange(entities);
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return ContextFactory.Get().Set<TEntity>().Where(predicate);
}
public TEntity Get(int id)
{
return ContextFactory.Get().Set<TEntity>().Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return ContextFactory.Get().Set<TEntity>().ToList();
}
public void Remove(TEntity entity)
{
ContextFactory.Get().Set<TEntity>().Remove(entity);
}
public void RemoveRange(IEnumerable<TEntity> entities)
{
ContextFactory.Get().Set<TEntity>().RemoveRange(entities);
}
public void Update(TEntity entity)
{
ContextFactory.Get().Set<TEntity>().Attach(entity);
ContextFactory.Get().Entry(entity).State = System.Data.Entity.EntityState.Modified;
}
}
New Unit Of Work Factory
When the factory is Create() method is called I call the context factory's Create() method to create a new context.
public class UnitOfWorkFactory : IUnitOfWorkFactory
{
private IContextFactory _contextFactory;
public UnitOfWorkFactory(IContextFactory factory)
{
_contextFactory = factory;
}
public UnitOfWork Create()
{
return new UnitOfWork(_contextFactory.Create());
}
}
By doing it this way I am now able to inject my context factory into all my repositories. I attempted to use the Ninject scopes mentioned above in the original question but ended up causing issues with injecting two separate contexts, one in my unit of work factory and one in my repositories.
So that I can store the user's screen preferences, I have ScreenSettings entity that I want to retrieve when the program starts and save when the program ends.
For this reason I don't want to keep the context open.
I am wondering about the best way to do this.
I have tried the following
however I am not comfortable with the SaveSettings function because it deletes and re-adds the object.
How do I save changes to the object without actually replacing it?
namespace ClassLibrary1
{
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
//Domain Class
public class ScreenSetting
{
#region Properties
public int Id { get; set; }
[Required]
public int WindowLeft { get; set; }
[Required]
public int WindowTop { get; set; }
#endregion
}
// Context
public class Context : DbContext
{
#region Properties
public DbSet<ScreenSetting> ScreenSettings { get; set; }
#endregion
}
// UI
public class UI
{
#region Public Methods
// Get the settings object
public ScreenSetting GetSettings(int SettingsId)
{
var Db = new Context();
ScreenSetting settings = Db.ScreenSettings.Find(SettingsId);
if (settings == null)
{
settings = new ScreenSetting { Id = SettingsId, WindowTop = 100, WindowLeft = 100 };
Db.ScreenSettings.Add(settings);
}
Db.Dispose();
return settings;
}
// Save the settings object
public void SaveSettings(ScreenSetting settings)
{
var Db = new Context();
ScreenSetting oldSettings = Db.ScreenSettings.Find(settings.Id);
if (oldSettings == null)
{
Db.ScreenSettings.Add(settings);
}
else
{
Db.ScreenSettings.Remove(oldSettings);
Db.ScreenSettings.Add(settings);
}
Db.Dispose();
}
public void test()
{
ScreenSetting setting = this.GetSettings(1);
setting.WindowLeft = 500;
setting.WindowTop = 500;
this.SaveSettings(setting);
}
#endregion
#region Methods
private static void Main()
{
var o = new UI();
o.test();
}
#endregion
}
}
You ran into a common pattern, update or insert, which is so common that it's got a name: upsert. When a pattern is common, usually there also is a common solution.
In System.Data.Entity.Migrations there is an extension method AddOrUpdate that does exactly what you want:
public void SaveSettings(ScreenSetting settings)
{
using (var db = new Context())
{
db.ScreenSettings.AddOrUpdate(settings);
db.SaveChanges();
}
}
How do I structure the database? I use a repository pattern with entity framework and code-first to code the models.
For example: I want an admin to set a string to be appended to every username.
I was thinking about a key-value table (settings) that has the following columns? SettingsId, Name, Value. With this method, I would need to manually go in, create a record Name:AppendedToUsername, Value:nil. I would then write repository methods specifically for each settings I need. For eg.
public string GetAppenedToUsername()
{
db.Settings.FirstOrDefault(s => s.Name == "AppendedToUsername").Select(s => s.Value);
}
Is there any better way of designing this database?
It's a good solution. I only recommend to create a strongly typed class with these settings and use caching for them.
Cache service:
public class CacheService
{
private ObjectCache Cache
{
get { return MemoryCache.Default; }
}
public object Get(string key)
{
return Cache[key];
}
public void Set(string key, object data, int cacheTime)
{
CacheItemPolicy policy = new CacheItemPolicy();
policy.AbsoluteExpiration = DateTime.Now.AddMinutes(cacheTime);
Cache.Add(new CacheItem(key, data), policy);
}
public bool IsSet(string key)
{
return (Cache[key] != null);
}
public void Invalidate(string key)
{
Cache.Remove(key);
}
}
AppSetting:
public class AppSetting
{
public const string StrSettingKey = "StrSetting";
private CacheService CacheService { get; set; }
private DbContext DbContext { get; set; }
public AppSetting(ICacheService cache, DbContext db)
{
CacheService = CacheService;
DbContext = db;
}
public string StrSetting
{
get
{
if (CacheService.IsSet(StrSettingKey))
{
return (string) CacheService.Get(StrSettingKey);
}
else
{
var value = DbContext.Settings.Single(s => s.Name == StrSettingKey).Select(s => s.Value);
CacheService.Set(StrSettingKey, value, 60); //one hour
return value;
}
}
set
{
var item = DbContext.Settings.Single(s => s.Name == StrSettingKey);
item.Value = value;
DbContext.SaveChanges();
CacheService.Set(StrSettingKey, value);
}
}
}
I have a very simple server model that includes a parent entity with a [Composition] list of child entities. In my client, I have 2 functions. One function removes all the child entities from the parent and the other removes all and also edits a property on the parent entity.
When I simply remove all child entities and SubmitChanges(), all is well.
When I remove all child entities and edit the parent and SubmitChanges(), there are still pending changes (HasChanges == true) when the SubmitChanges() callback is fired.
I am using Silveright 4 RTM and RIA Services 1.0 RTM.
Any ideas what is going on here?
Here are the server entities:
public class RegionDto
{
public RegionDto()
{
Cities = new List<CityDto>();
}
[Key]
public int Id { get; set; }
public string Name { get; set; }
[Include]
[Composition]
[Association("RegionDto_CityDto", "Id", "RegionId")]
public List<CityDto> Cities { get; set; }
}
public class CityDto
{
[Key]
public int Id { get; set; }
public int RegionId { get; set; }
public string Name { get; set; }
}
And here is the client code:
public static class CState
{
private static RegionDomainContext _domainContext;
public static RegionDomainContext DomainContext
{
get
{
if (_domainContext == null)
{
_domainContext = new RegionDomainContext();
}
return _domainContext;
}
}
public static void SaveChanges()
{
DomainContext.SubmitChanges(op =>
{
if (DomainContext.HasChanges && !DomainContext.IsSubmitting)
{
var w = new ChildWindow();
w.Content = "The DomainContext still has unsaved changes.";
w.Show();
}
}, null);
}
}
public partial class MainPage : UserControl
{
private void ClearCitiesEditRegion(object sender, RoutedEventArgs e)
{
var region = (RegionDto)regionList.SelectedItem;
if (region != null)
{
region.Name += "*";
while (region.Cities.Count > 0)
{
region.Cities.Remove(region.Cities.First());
}
CState.SaveChanges();
}
}
private void ClearCities(object sender, RoutedEventArgs e)
{
var region = (RegionDto)regionList.SelectedItem;
if (region != null)
{
while (region.Cities.Count > 0)
{
region.Cities.Remove(region.Cities.First());
}
CState.SaveChanges();
}
}
}
When you run this code the ChildWindow is only shown when you the ClearCitiesEditRegion() method is called. The only difference between this and the ClearCities() method is the line where I edit the region.Name property.
You can also download a sample project that reproduces this here: http://dl.dropbox.com/u/2393192/RIA_Services_Problem.zip
I received an answer to this on the Silverlight forums. Apparently this is a bug in RIA Service 1.0. The following is Matthew's response on the Silverlight forums.
Yes, I've confirmed this is a bug.
Thanks for reporting it and providing
the repro. As you discovered, the bug
will only repro in composition
scenarios where the parent has been
modified in addition to one or more
children. The workaround is to do an
explicit AcceptChanges if the submit
was successful. For example, here is
the code you'd write in a submit
callback:
if (!submitOperation.HasError)
{
((IChangeTracking)ctxt.EntityContainer).AcceptChanges();
}
This will accept all changes and reset
change state correctly.
I am just learning MVVM with MEF and already see the benefits but I am a little confused about some implementation details. The app I am building has several Models that do the same with with different entities (WCF RIA Services exposing a Entity framework object) and I would like to avoid implementing a similar interface/model for each view I need and the following is what I have come up with though it currently doesn't work.
The common interface has a new completed event for each model that implements the base model, this was the easiest way I could implement a common class as the compiler did not like casting from a child to the base type.
The code as it currently sits compiles and runs but the is a null IModel being passed into the [ImportingConstructor] for the FaqViewModel class.
I have a common interface (simplified for posting) defined as follows, this should look familiar to those who have seen Shawn Wildermuth's RIAXboxGames sample.
public interface IModel
{
void GetItemsAsync();
event EventHandler<EntityResultsArgs<faq>> GetFaqsComplete;
}
A base method that implements the interface
public class ModelBase : IModel
{
public virtual void GetItemsAsync() { }
public virtual event EventHandler<EntityResultsArgs<faq>> GetFaqsComplete;
protected void PerformQuery<T>(EntityQuery<T> qry, EventHandler<EntityResultsArgs<T>> evt) where T : Entity
{
Context.Load(qry, r =>
{
if (evt == null) return;
try
{
if (r.HasError)
{
evt(this, new EntityResultsArgs<T>(r.Error));
}
else if (r.Entities.Count() > 0)
{
evt(this, new EntityResultsArgs<T>(r.Entities));
}
}
catch (Exception ex)
{
evt(this, new EntityResultsArgs<T>(ex));
}
}, null);
}
private DomainContext _domainContext;
protected DomainContext Context
{
get
{
if (_domainContext == null)
{
_domainContext = new DomainContext();
_domainContext.PropertyChanged += DomainContext_PropertyChanged;
}
return _domainContext;
}
}
void DomainContext_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "IsLoading":
AppMessages.IsBusyMessage.Send(_domainContext.IsLoading);
break;
case "IsSubmitting":
AppMessages.IsBusyMessage.Send(_domainContext.IsSubmitting);
break;
}
}
}
A model that implements the base model
[Export(ViewModelTypes.FaqViewModel, typeof(IModel))]
public class FaqModel : ModelBase
{
public override void GetItemsAsync()
{
PerformQuery(Context.GetFaqsQuery(), GetFaqsComplete);
}
public override event EventHandler<EntityResultsArgs<faq>> GetFaqsComplete;
}
A view model
[PartCreationPolicy(CreationPolicy.NonShared)]
[Export(ViewModelTypes.FaqViewModel)]
public class FaqViewModel : MyViewModelBase
{
private readonly IModel _model;
[ImportingConstructor]
public FaqViewModel(IModel model)
{
_model = model;
_model.GetFaqsComplete += Model_GetFaqsComplete;
_model.GetItemsAsync(); // Load FAQS on creation
}
private IEnumerable<faq> _faqs;
public IEnumerable<faq> Faqs
{
get { return _faqs; }
private set
{
if (value == _faqs) return;
_faqs = value;
RaisePropertyChanged("Faqs");
}
}
private faq _currentFaq;
public faq CurrentFaq
{
get { return _currentFaq; }
set
{
if (value == _currentFaq) return;
_currentFaq = value;
RaisePropertyChanged("CurrentFaq");
}
}
public void GetFaqsAsync()
{
_model.GetItemsAsync();
}
void Model_GetFaqsComplete(object sender, EntityResultsArgs<faq> e)
{
if (e.Error != null)
{
ErrorMessage = e.Error.Message;
}
else
{
Faqs = e.Results;
}
}
}
And then finally the Silverlight view itself
public partial class FrequentlyAskedQuestions
{
public FrequentlyAskedQuestions()
{
InitializeComponent();
if (!ViewModelBase.IsInDesignModeStatic)
{
// Use MEF To load the View Model
CompositionInitializer.SatisfyImports(this);
}
}
[Import(ViewModelTypes.FaqViewModel)]
public object ViewModel
{
set
{
DataContext = value;
}
}
}
It seems as though I am going down the wrong path with trying to refactor into multiple models. As seen here, http://msdn.microsoft.com/en-us/magazine/dd458800.aspx#id0090019 if would appear the best thing to do would be to think about the model as an instance of the EDMX class referenced via RIA Services. As such, the model should contain all methods and event handlers needed to access the DomainContext.
If anybody has other thoughts I would be open to them.
As a fellow noob, I am just starting to play with MEF, and I think I have identified a possible problem with your code. From your question, it sounds like your main problem is the null IModel reference.
Try changing this:
private readonly IModel _model;
to this:
[Import]
public IModel _model { get; set; }
I haven't yet played with how MEF likes private and readonly properties, so try setting to public and then verify that _model isn't null when you first try to use it.