Error in selecting value from RavenDB - c#

I am using RavenDB in my mvc4 project when store an object of class to RavenDB it works fine but when performing select operation it throws an error:
Object reference not set to an instance of an object
on all queries
RavenbaseController.cs
public class RavenBaseController : Controller
{
public IDocumentSession RavenSession { get; protected set; }
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
RavenSession = MvcApplication.Store.OpenSession("ravendbtesting");
}
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.IsChildAction)
return;
using (RavenSession)
{
if (filterContext.Exception != null)
return;
if (RavenSession != null)
RavenSession.SaveChanges();
}
}
}
Activation.cs
public class Activation : RavenBaseController
{
public string tokenid { get; set; }
public bool validate(string tid)
{
var query = from u in RavenSession.Query<Register>() where u.TokenId == tid select u;
foreach (var v in query)
{
v.IsApproved = true;
}
RavenSession.SaveChanges();
return true;
}
}
Queries tried:
var results = from u in RavenSession.Query<Register>()
where u.TokenId == tid
select u;
var query= RavenSession.Query<Register>()
.Where(x => x.TokenId == tid)
.ToList();
I can't understand why it is not working i am new to RavenDB
Update
All the queries work fine if run from controller but if run from class file, the error "Object reference not set to an instance of an object" occurs

If you try to instanciate var ctrl = new Activation(); and do ctrl.validate(x); it won't work as OnActionExecuting didn't run. That function is called automatically by the MVC framework when serving a request, not when manually testing.
Since MVC instantiates a new controller on each requests anyway, you should move the RavenSession initialization to the constructor since you do not seem to use any info in the request context:
public class RavenBaseController : Controller
{
public IDocumentSession RavenSession { get; protected set; }
public RavenBaseController()
{
RavenSession = MvcApplication.Store.OpenSession("ravendbtesting");
}
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.IsChildAction)
return;
using (RavenSession)
{
if (filterContext.Exception != null)
return;
if (RavenSession != null)
RavenSession.SaveChanges();
}
}
}
The even better way is to use Dependency Injection to pass the session as a constructor parameter, but the above should work for you.

Related

how to perform a runtime view update when using ResourceViewLocationProvider

Im runing a nancyfx with owin on centos 6.5 with mono 5.10.0.140, I change the default ViewLocationProvider to ResourceViewLocationProvider for the default ViewLocationProvider causes memory leak of somekind after running for days, and the ResourceViewLocationProvider dont have the same problem. I would like to hot update Views just like what we can do with a default ViewLocationProvider, but it seems impossibe when googling around.
I did find a partial solution though, by implenting a custom IViewLocator and a IViewCache, I did achieve someking of hot update. But It didn`t feel right aside from those ugly static class
//Here is what I did in the custom IViewLocator
//...class definition fallback viewlocator and other staffs
private static ConcurrentDictionary<string, ViewLocationResult> _cachedViewLocationResults;
//..other code
public ViewLocationResult LocateView(string viewName, NancyContext context)
{
//...lock and others
if (_cachedViewLocationResults != null && _cachedViewLocationResults.ContainsKey(viewName))
{
return _cachedViewLocationResults[viewName];
}
//...lock and others
return fallbackViewLocator.LocateView(viewName, context);
}
//...other class
//here is how I update Views
public static void UpdateCachedView(IDictionary<string, ViewLocationResult> replacements)
{
lock (CacheLock)
{
if(_cachedViewLocationResults == null)_cachedViewLocationResults = new ConcurrentDictionary<string, ViewLocationResult>();
foreach (var replace in replacements)
{
_cachedViewLocationResults.AddOrUpdate(replace.Key, x=>replacements[x], (x,y)=>y);
}
}
}
//END OF IViewLocator
//here is what I did in the custom IViewCache
//another static for ViewCache to tell if the view has been updated
public static List<ViewLocationResult> Exceptions { get; private set; }
//...some other code
//here is how I ignore the old cache
public TCompiledView GetOrAdd<TCompiledView>(ViewLocationResult viewLocationResult, Func<ViewLocationResult, TCompiledView> valueFactory)
{
if (Exceptions.Any(x=>x.Name == viewLocationResult.Name && x.Location == viewLocationResult.Location && x.Extension == viewLocationResult.Extension))
{
object old;
this.cache.TryRemove(viewLocationResult, out old);
Exceptions.Remove(viewLocationResult);
}
return (TCompiledView)this.cache.GetOrAdd(viewLocationResult, x => valueFactory(x));
}
With those implentions and a little bit of settings on the bootstrapper plus a router for some mysql update, I can update the View the way I want, but here is the problem:
1. now I have to manually map all the Location,Name,Extension for the ViewLocationResult to use and there are too many of them (243...), I would like to use the some sort of built-in function to identify the changes, something like the IsStale function of the ViewLocationResult, but I didnt know which and how...
2. those static class are ugly and I think it could be problematic but I didnt know a better way to replace them.
Could some one kindly give me a hint, thank in advance.
Well, I finally figure out how to do this myself, just in case anyone else want to use the same method as I do, Here is how you update your view in memory:
Make a interface
public interface INewViewLocationResultProvider
{
bool UseCachedView { get; set; }
ViewLocationResult GetNewerVersion(string viewName, NancyContext context);
void UpdateCachedView(IDictionary<string, ViewLocationResult> replacements);
}
Make a new ViewLocationResultProvider
public class ConcurrentNewViewLocationResultProvider : INewViewLocationResultProvider
{
private Dictionary<string, ViewLocationResult> _cachedViewLocationResults;
private readonly object _cacheLock = new object();
public bool UseCachedView { get; set; }
public ConcurrentNewViewLocationResultProvider()
{
lock (_cacheLock)
{
if(_cachedViewLocationResults == null)_cachedViewLocationResults = new Dictionary<string, ViewLocationResult>();
}
}
public ViewLocationResult GetNewerVersion(string viewName, NancyContext context)
{
if (UseCachedView)
{
if (Monitor.TryEnter(_cacheLock, TimeSpan.FromMilliseconds(20)))
{
try
{
if (_cachedViewLocationResults != null && _cachedViewLocationResults.ContainsKey(viewName))
{
return _cachedViewLocationResults[viewName];
}
}
finally
{
Monitor.Exit(_cacheLock);
}
}
}
return null;
}
public void UpdateCachedView(IDictionary<string, ViewLocationResult> replacements)
{
lock (_cacheLock)
{
if(_cachedViewLocationResults == null)_cachedViewLocationResults = new Dictionary<string, ViewLocationResult>();
foreach (var replace in replacements)
{
if (_cachedViewLocationResults.ContainsKey(replace.Key))
{
_cachedViewLocationResults[replace.Key] = replace.Value;
}
else
{
_cachedViewLocationResults.Add(replace.Key,replace.Value);
}
}
}
}
}
In your Bootstrapper,register the new ViewLocationResultProvider with tinyIoc or equivalent
container.Register<INewViewLocationResultProvider, ConcurrentNewViewLocationResultProvider>().AsSingleton();
Make a derived class from ViewLocationResult
public class OneTimeUsedViewLocationResult : ViewLocationResult
{
private bool _used = false;
public OneTimeUsedViewLocationResult(string location, string name, string extension, Func<TextReader> contents)
: base(location, name, extension, contents)
{
}
public override bool IsStale()
{
if (_used) return false;
_used = true;
return true;
}
}
And a new IViewLocator:
public class CachedViewLocator : IViewLocator
{
private readonly INewViewLocationResultProvider _newVersion;
private readonly DefaultViewLocator _fallbackViewLocator;
public CachedViewLocator(IViewLocationProvider viewLocationProvider, IEnumerable<IViewEngine> viewEngines, INewViewLocationResultProvider newVersion)
{
_fallbackViewLocator = new DefaultViewLocator(viewLocationProvider, viewEngines);
_newVersion = newVersion;
}
public ViewLocationResult LocateView(string viewName, NancyContext context)
{
if (_newVersion.UseCachedView)
{
var result = _newVersion.GetNewerVersion(viewName, context);
if (result != null) return result;
}
return _fallbackViewLocator.LocateView(viewName, context);
}
public IEnumerable<ViewLocationResult> GetAllCurrentlyDiscoveredViews()
{
return _fallbackViewLocator.GetAllCurrentlyDiscoveredViews();
}
}
}
Tell nancy about the new ViewLocator
protected override NancyInternalConfiguration InternalConfiguration
{
get
{
return NancyInternalConfiguration.WithOverrides
(
nic =>
{
nic.ViewLocationProvider = typeof(ResourceViewLocationProvider);//use this or your equivalent
nic.ViewLocator = typeof(CachedViewLocator);
}
);
}
}
Then you can update it through a API like this:
public class YourModule : NancyModule
{
public YourModule(INewViewLocationResultProvider provider)
{
Get["/yourupdateinterface"] = param =>
{
if(!provider.UseCachedView) return HttpStatusCode.BadRequest;//in case you turn off the hot update
//you can serialize your OneTimeUsedViewLocationResult with Newtonsoft.Json and store those views in any database, like mysql, redis, and load them here
//data mock up
TextReader tr = new StringReader(Resources.TextMain);
var vlr = new OneTimeUsedViewLocationResult("","index","cshtml",()=>tr);
var dir = new Dictionary<string, ViewLocationResult> {{"index",vlr}};
//mock up ends
provider.UpdateCachedView(dir);
return HttpStatusCode.OK;
}
}
}
Note: Those code above doesn't solve the manually map all the Location,Name,Extension for the ViewLocationResult thing menthions in my question, but since I endup build a view editor for my colleges to upload their views, I don't need to solve it anymore.

HttpSessionStateBase losing property values of inherited type

We are using HttpSessionStateBase to store messages in a set up similar to this working example:
public class HttpSessionMessageDisplayFetch : IMessageDisplayFetch
{
protected HttpSessionStateBase _session;
private IList<ICoreMessage> messages
{
get
{
if (_session[EchoCoreConstants.MESSAGE_KEY] == null)
_session[EchoCoreConstants.MESSAGE_KEY] = new List<ICoreMessage>();
return _session[EchoCoreConstants.MESSAGE_KEY] as IList<ICoreMessage>;
}
}
public HttpSessionMessageDisplayFetch()
{
if (HttpContext.Current != null)
_session = new HttpSessionStateWrapper(HttpContext.Current.Session);
}
public void AddMessage(ICoreMessage message)
{
if (message != null)
messages.Add(message);
}
public IEnumerable<IResultPresentation> FlushMessagesAsPresentations(IResultFormatter formatter)
{
var mToReturn = messages.Select(m => m.GetPresentation(formatter)).ToList();
messages.Clear();
return mToReturn;
}
}
When we pass in a QualityExplicitlySetMessage (which inherits from ICoreMessage, see below) it is saved correctly to messages.
This is how the object looks after being inserted into the messages list, at the end of AddMessage(ICoreMessage message) above.
But when we come to access it after changing controllers the inherited member's properties are null, which causes a variety of null reference exceptions.
This is how the object now looks after we call FlushMessagesAsPresentations. I've commented out var mToReturn... as this tries to access one of these null ref properties.
I'd like to ask the following:
Why is the HttpSessionStateBase failing to capture these values taken
by the inherited type?
Is this an issue in saving to the HttpSession or in retrieving?
Is this anything to do with, as I suspect, inheritance?
Or is the fact I'm potentially calling a new controller that dependency injects the HttpSessionMessageDisplayFetch causing an issue?
I'm a first-time poster so please let me know if I'm making any kind of faux pas - Super keen to learn! Any input is very welcome.
Some potentially useful code snippets:
QualityExplicitlySetMessage
public class QualityExplicitlySetMessage : QualityChangeMessage
{
public QualityExplicitlySetMessage(IQPossession before, IQPossession after, IQEffect qEffect)
: base(before, after, qEffect)
{
IsSetToExactly = true;
}
}
QualityChangeMessage - Working example
public abstract class QualityChangeMessage : CoreMessage, IQualityChangeMessage
{
protected PossessionChange Change;
public PossessionChange GetPossessionChange()
{
return Change;
}
protected QualityChangeMessage(IQPossession before, IQPossession after, IQEffect qEffect)
{
Change = new PossessionChange(before, after, qEffect);
StoreQualityInfo(qEffect.AssociatedQuality);
}
public override IResultPresentation GetPresentation(IResultFormatter formatter)
{
return formatter.GetQualityResult(this);
}
#region IQualityChangeMessage implementation
public int LevelBefore
{
get { return Change.Before.Level; }
}
//... And so on with values dependent on the Change property.
}
CoreMessage - Working example
public abstract class CoreMessage : ICoreMessage
{
public string MessageType
{
get { return GetType().ToString(); }
}
public string ImageTooltip
{
get { return _imagetooltip; }
set { _imagetooltip = value; }
}
public string Image
{
get { return _image; }
set { _image = value; }
}
public int? RelevantQualityId { get; set; }
protected void StoreQualityInfo(Quality q)
{
PyramidNumberIncreaseLimit = q.PyramidNumberIncreaseLimit;
RelevantQualityId = q.Id;
RelevantQualityName = q.Name;
ImageTooltip = "<strong>" + q.Name + "</strong><br/>" + q.Description + "<br>" +
q.EnhancementsDescription;
Image = q.Image;
}
public virtual IResultPresentation GetPresentation(IResultFormatter formatter)
{
return formatter.GetResult(this);
}
}
UserController - Working example.
public partial class UserController : Controller
{
private readonly IMessageDisplayFetch _messageDisplayFetch;
public UserController(IMessageDisplayFetch messageDisplayFetch)
{
_messageDisplayFetch = messageDisplayFetch;
}
public virtual ActionResult MessagesForStoryletWindow()
{
var activeChar = _us.CurrentCharacter();
IEnumerable<IResultPresentation> messages;
messages = _messageDisplayFetch.FlushMessagesAsPresentations(_storyFormatter);
var vd = new MessagesViewData(messages)
{
Character = new CharacterViewData(activeChar),
};
return View(Views.Messages, vd);
}
}

How do I alter the RenderingContext in a pipeline?

I need a pipeline to intercept the building of the sitecore RenderingContext, specifically I need to alter the RenderingContext.Current.Rendering.DataSource attribute on the fly.
I need to do this because I've added a variable into my Datasource in sitecore. I was manipulating this in the controller but when I turn on the experience editor it falls over before it even hit's my controller. I'm guessing somehting higher up needs the datasource to be valid.
After a bit of digging about I discovered this pipeline:
namespace Sitecore.Mvc.Pipelines.Response.RenderRendering
{
public class EnterRenderingContext : RenderRenderingProcessor
{
public override void Process(RenderRenderingArgs args)
{
Assert.ArgumentNotNull(args, "args");
if (args.Rendered)
{
return;
}
this.EnterContext(args.Rendering, args);
}
protected virtual void EnterContext(Rendering rendering, RenderRenderingArgs args)
{
IDisposable item = RenderingContext.EnterContext(rendering);
args.Disposables.Add(item);
}
}
}
Reflected out of Sitecore.Mvc.dll
I can now replace this pipeline with my own and change the values of the RenderingContext before they're built:
public class RedrowEnterRenderingContext : Sitecore.Mvc.Pipelines.Response.RenderRendering.EnterRenderingContext
{
private const string _developmentKeyword = "$development";
private IDevelopmentQueryServiceV2 _coUkDevelopmentQueryService = ServiceLocator.Current.GetInstance<IDevelopmentQueryServiceV2>();
protected override void EnterContext(Rendering rendering, RenderRenderingArgs args)
{
//Make your changes to the items that are used to build the context here
if (args.PageContext != null &&
args.PageContext.Item != null &&
args.Rendering.DataSource.Contains(_developmentKeyword) &&
args.PageContext.Item.TemplateID.Guid == TemplateIdConst.V2Development)
{
args.Rendering.DataSource = args.Rendering.DataSource.Replace(_developmentKeyword,
args.PageContext.Item.Paths.Path);
}
//build the context using the existing functionality
base.EnterContext(rendering, args);
}
}
I'm manipulating the datasource in a specific scenario but this code could be adapted to do many jobs.
you register this thus:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<mvc.renderRendering>
<processor type="Namespace.MyEnterRenderingContext, DLLName"
patch:instead="*[#type='Sitecore.Mvc.Pipelines.Response.RenderRendering.EnterRenderingContext, Sitecore.Mvc']"/>
</mvc.renderRendering>
</pipelines>
</sitecore>
</configuration>
One issue with this is that it shows up in the BrokenLinkValidator. You can override this though and create your own:
[Serializable]
public class MyBrokenLinksValidator : BrokenLinkValidator
{
public RedrowBrokenLinksValidator() : base()
{
}
public RedrowBrokenLinksValidator(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context)
{
}
protected override ValidatorResult Evaluate()
{
ValidatorResult returnVal = base.Evaluate();
if (returnVal != ValidatorResult.Valid)
{
Item obj = base.GetItem();
ItemLink[] brokenLinks = obj.Links.GetBrokenLinks(false);
//are all the broken links basically because they are contextual?
if (brokenLinks.All(a => a.TargetPath.Contains("$development")))
{
foreach (ItemLink brokenLink in brokenLinks)
{
Database database = Sitecore.Configuration.Factory.GetDatabase("master");
//try again but replacing the varible with a context
var secondTryPath = brokenLink.TargetPath.Replace(
"$development", obj.Paths.Path);
Item secondTryItem = database.GetItem(secondTryPath);
if (secondTryItem == null)
return returnVal;
}
//if we've got here then all the links are valid when adding the context
return ValidatorResult.Valid;
}
}
return returnVal;
}
}

Multiple authorization attributes that are aware of each other

I have a very simple scenario. I want to decorate my controllers/actions with a custom authorization attribute. Authorization should be granted if any of the attributes is valid. For example,
[MyAuth(1)]
[MyAuth(2)]
public class MyController : Controller
{
...
}
I cannot combine the parameters into a single authorization attribute. The above example is a simplified example, only.
If either attribute authorizes the user, I want the user to be authorized. I assumed that ActionFilterAttribute or AuthorizeAttribute would have the means to see what other filters have been executed and are waiting to be executed, but no such luck.
How can I accomplish this? Since the attributes don't seem to have any awareness, maybe an HttpModule? A custom ControllerActionInvoker?
I managed to get this to work last night. My solution is below. The attribute is pretty standard and I've trimmed the actual authorization parts. The interesting stuff happens in HasAssignedAcccessActionInvoker.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class RequiresAssignedAccess : AuthorizeAttribute
{
public int AccessType { get; private set; }
public int IdType { get; private set; }
public int IdValue { get; private set; }
public int Level { get; private set; }
public RequiresAssignedAccess(int accessType, int idType, int idValue, int level)
{
...
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (!base.AuthorizeCore(httpContext))
return false;
bool retval = ...
return retval;
}
}
HasAssignedAcccessActionInvoker inherits from the standard action invoker, but I overrode the InvokeAuthorizationFilters method to add the authorization logic we need. The standard invoker just spins through the authorization filters and if any of them returns a result, it breaks the loop.
public class HasAssignedAcccessActionInvoker : ControllerActionInvoker
{
protected override AuthorizationContext InvokeAuthorizationFilters(ControllerContext controllerContext, IList<IAuthorizationFilter> filters, ActionDescriptor actionDescriptor)
{
AuthorizationContext authCtx = new AuthorizationContext(controllerContext, actionDescriptor);
/*
* If any of the filters are RequiresAssignedAccess, default this to false. One of them must authorize the user.
*/
bool hasAccess = !filters.Any(f => f is RequiresAssignedAccess);
foreach (IAuthorizationFilter current in filters)
{
/*
* This sets authorizationContext.Result, usually to an instance of HttpUnauthorizedResult
*/
current.OnAuthorization(authCtx);
if (current is RequiresAssignedAccess)
{
if (authCtx.Result == null)
{
hasAccess = true;
}
else if (authCtx.Result is HttpUnauthorizedResult)
{
authCtx.Result = null;
}
continue;
}
if (authCtx.Result != null)
break;
}
if (!hasAccess && authCtx.Result == null)
authCtx.Result = new HttpUnauthorizedResult();
return authCtx;
}
}
I had to look at MVC's internals with ILSpy to figure this out. For reference, this is the overridden version of that method:
protected virtual AuthorizationContext InvokeAuthorizationFilters(ControllerContext controllerContext, IList<IAuthorizationFilter> filters, ActionDescriptor actionDescriptor)
{
AuthorizationContext authorizationContext = new AuthorizationContext(controllerContext, actionDescriptor);
foreach (IAuthorizationFilter current in filters)
{
current.OnAuthorization(authorizationContext);
if (authorizationContext.Result != null)
{
break;
}
}
return authorizationContext;
}
Lastly, to wire this up and make everything possible, our controllers inherit from BaseController, which now returns the new invoker.
public class BaseController : Controller
{
protected override IActionInvoker CreateActionInvoker()
{
return new HasAssignedAcccessActionInvoker();
}
}
As far as I know, you cannot chain [Authorize] attributes in the manner that you want because they all have to pass (AND) and not (OR) behavior. However, the combining of the items into one does not cause you to have to do some magic string manipulation, regardless of the number of parameters that you need to pass to it. You can define your own set of parameters that are available to the Authorize attribute.
public class SuperCoolAuthorize : AuthorizationAttribute
{
public string Parameter1{get;set;}
public string Parameter2{get;set;}
public int Parameter3{get;set;}
public string Parameter4{get;set;}
public override void OnAuthorization(AuthorizationContext filterContext)
{
// your custom behaviour
}
}
And on your controller/action method
[Authorize(Parameter1 = "Foo", Parameter2 = "Bar", Parameter3 = 47, Parameter4 = string.Empty)
public ActionResult MyControllerAction(){
...
}
A great post on some other considerations on custom Authorizing attributes I came across in helping to formulate this answer.
public class AuthUserAttribute : AuthorizeAttribute {
public string[] SecurityGroups;
public string Groups { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext) {
bool valid = false;
var user = UserInformation.Current;
if (user.SecurityGroups.Select(x => x).Intersect(this.SecurityGroups).Any()) {
valid = true;
}
if (user.SecurityGroups.Select(x => x).Intersect(new string[] { "IT Administrators" }).Any()) {
valid = true;
}
return valid;
}
public override void OnAuthorization(AuthorizationContext filterContext) {
if (!this.AuthorizeCore(filterContext.HttpContext)) {
if (UserInformation.Current.SecurityGroups.Count == 0) {
filterContext.Result = new RedirectResult(string.Format("/oa?ReturnUrl={0}", filterContext.HttpContext.Request.RawUrl));
}
else {
filterContext.Result = new RedirectResult(string.Format("/oa/user/permissions?ReturnUrl={0}", filterContext.HttpContext.Request.RawUrl));
}
}
else {
base.OnAuthorization(filterContext);
}
}
}
then I decorate with
[AuthUser(SecurityGroups = new string[] { "Data1", "Data2" })]
public ActionResult ForYourEyesOnly() {
}
We'll see if anyone catches the Bond reference. LOL

EF - Tries to add a new object instead of using existing?

How come that when I try to add a case by using the bool method in CaseRepository.cs by assign a user to the case object to determine which user is the owner of the case (who created it?) - but when I try to assign it then it tries to add a new User object to the table too although it's an existing User I'm passing in as parameter?
In short: I'm trying to let a User create a case and assign that case to the user.
The reason for mapping MembershipUser to User object is to enable the EF (code first) to could use it for CRUD operations.
// CaseController.cs
[AuthWhere(AuthorizeRole.Developer)]
[HttpPost]
public ActionResult Create(CreateCaseViewModel model)
{
var success = false;
string message;
User user = Mapper.Map<MembershipUser, User>(_membershipService.GetUserByUserName(User.Identity.Name));
Case createCase = _caseService.CreateCase(model.Topic, model.Message);
bool addCase = _caseService.AddCase(createCase, user);
if(!addCase)
{
message = ControllerResources.CaseCreateFail;
}
else
{
success = true;
message = ControllerResources.CaseCreateSuccess;
}
return Json(new
{
Success = success,
Message = message,
Partial = RenderPartialViewToString("List", GetCases)
});
}
// RepositoryBase.cs
public class RepositoryBase<T> : IRepository<T> where T : class
{
public IDbContext Context { get; private set; }
public IDbSet<T> ObjectSet { get; private set; }
public RepositoryBase(IDbContext context)
{
Contract.Requires(context != null);
Context = context;
if (context != null)
{
ObjectSet = Context.CreateDbSet<T>();
if (ObjectSet == null)
{
throw new InvalidOperationException();
}
}
}
[ContractInvariantMethod]
private void Invariant()
{
Contract.Invariant(Context != null);
Contract.Invariant(ObjectSet != null);
}
public IRepository<T> Add(T entity)
{
ObjectSet.Add(entity);
return this;
}
public IRepository<T> SaveChanges()
{
Context.SaveChanges();
return this;
}
}
// CaseRepository.cs
public class CaseRepository : RepositoryBase<Case>, ICaseRepository
{
public CaseRepository(IDbContext context)
: base(context)
{
Contract.Requires(context != null);
}
public bool AddCase(Case #case, User user)
{
#case.User = user;
ObjectSet.Add(#case);
Context.SaveChanges();
return true;
}
}
If you are modifying existing object, then you don't need to add to context again. Therefore just remove this line for updates:
ObjectSet.Add(#case);
You may need to consider to create two separate methods, Add and Update in CaseRepository class.
Forgot to make 2 of my mappings in the POCO classes virtual.

Categories