Extending entity framework classes - c#

Even many Q/A on the subject, I didn't find a clear answer for this question:
What's the best design practice for adding business rules (i.e, validations) to entity classes.
I simply want to check some validations before setting the underlying entity value:
public Property
{
get { return base.Property; }
set
{
// Do some validations or other business logic
base.Property = value;
}
}
It doesn't make sense to create a new class from scratch in BLL when all properties are already there in entity class. On the other hand, entity classes need to be extended with business logic rules.
Using interface need extra work, because a change in DAL (entity) would be reflected in both interface and BLL class.
I'm not sure if inheriting from entity class and overriding it's properties and adding extra properties and methods is a good idea or not.
A sample pseudo code in more helpful to me.
Thanks

I would like to elaborate on Stephen Cleary's answer. He is correct in using the partial class/methods to handle business rules in EF. However, he did not go into much detail about what to do within that partial class/method. I created a URL shortening service on my blog to use as an example for this. My ShortURL entity has only two columns/properties. Url and ID.
I wanted to validate that the URL being shortened is a valid URL before it actually stores it in the database through EF. So I created a partial class and method like so:
public partial class ShortURL
{
partial void OnUrlChanging(string url)
{
if (!Regex.IsMatch(url, #"(^((http|ftp|https):\/\/|www\.)[\w\-_]+(\.[\w\-_]+)+([\w\-\.,#?^=%&:/~\+#]*[\w\-\#?^=%&/~\+#])?)"))
throw new Exception("Not a valid URL.");
}
}
This stopped EF from changing the property, leaving it NULL. But that's all it did. It didn't give me an easy way to get at the error message and display it to the user (that I am aware of EDIT: According to http://www.sellsbrothers.com/posts/Details/12700 IDataErrorInfo is the only way to get the error message to display properly in ASP.NET MVC) so I followed another example I found in the dark recesses of the web somewhere and I made my partial class inherit from IDataErrorInfo. I then implemented the interface and included a private dictionary object to store error messages in.
public partial class ShortURL : IDataErrorInfo
{
private Dictionary<string, string> errors = new Dictionary<string, string>();
partial void OnUrlChanging(string url)
{
if (!Regex.IsMatch(url, #"(^((http|ftp|https):\/\/|www\.)[\w\-_]+(\.[\w\-_]+)+([\w\-\.,#?^=%&:/~\+#]*[\w\-\#?^=%&/~\+#])?)"))
errors.Add("Url", "Not a valid URL.");
}
public string Error
{
get { return string.Empty; } //I never use this so I just return empty.
}
public string this[string columnName]
{
get
{
if (errors.ContainsKey(columnName))
return errors[columnName];
return string.Empty; //Return empty if no error in dictionary.
}
}
}
Now, I have a fully-functioning way to store, retrieve, and display error messages. Now back in my controller (in MVC) I am able to do if (!ModelState.IsValid)
[HttpPost]
public ViewResult URLShortener(ShortURL shortURL)
{
if (!ModelState.IsValid)
return View();
shortURL.Url = shortURL.Url.ToLower().StartsWith("www.") ? "http://" + shortURL.Url : shortURL.Url;
shortURLRepository.AddShortURL(shortURL);
object model = "http://www.u413.com/" + ShortCodes.LongToShortCode(shortURL.UrlID);
//Not related to this answer but I had to cast my string as a generic object because the View() method has a (string, string) constructor that does something totally different. My view actually uses string as the model. I know I know, I could have just used ViewBag.
return View("ShowUrl", model);
}
There ya go. A working example of how to not only extend EF's partial methods, but also how to propagate the validation back to the UI. Let me know if anything needs improving or if there was something I missed.

Check out your EF designer-generated code.
Each property Property is actually implemented like this:
public global::System.String Property
{
get
{
return _Property;
}
set
{
OnPropertyChanging(value);
ReportPropertyChanging("Property");
_Property = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("Property");
OnPropertyChanged();
}
}
private global::System.String _Property;
partial void OnPropertyChanging(global::System.String value);
partial void OnPropertyChanged();
The partial method On-Property-Changing is where you can do single-property validation or business logic.

Xaqron, the best way I have found it to use Partial Classes, for example, if you have a class in your EF called PropertyListing you can use a partial class like this:
Partial Public Class PropertyListing
Inherits EntityObject
'Do something here
End Class
You can now extend the class as little or as much as you want without much fuss. The example is in VB but you get the jist of it

Related

ASP .NET Model Validation: Is it ok to access DBContext inside the Model?

Working with ASP .NET MVC I have a model called Entity1 and I need to do a custom validation inside of it.
I searched for a while and found out that implementing IValidatableObject I could implement the Validate method to do what I want. Now the question I have in this process is that I need to validate a property of Entity1 with another property of related Entity2 (by related I mean Data base relationship).
What I have is this:
public partial class Entity1: IValidatableObject
{
private EntitiesContext db = new EntitiesContext ();
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!Validation1())
{
yield return new ValidationResult(#"Error message.", new[] { "Property1" });
}
}
private bool Validation1()
{
if (this.Property1 != db.Entity2.First().Property2)
{
return false;
}
return true;
}
}
This is a simplified example of what I'm trying to do, but what I'm trying to figure out is if the use of "db" object to make the validation is well done right there. Obviously I can polish it later with some Dependency Injection, but I want to be sure if this is the right way to make that kind of validation or if another way exists to achieve exactly that.
PS: I tried to access the relationship like this too, but the relationship is always null:
this.Property1 != this.Entity2.Property2
In the later, this.Entity2 is always null.
Thanks in advance! :)

How to make grid operations work with custom property in EF?

In a ASP.NET MVC 5 web site I have a GridView using the devexpress component binding using the LINQ method.
EF generated a partial class to map a table that i use to display in that gridview.
In this partial class generated by the EF i have a ID_Status property wich has a corresponding description in other table. I made another partial class to deal with this custom Property and it works ok, except when i try to make a 'Sort' operation clicking on the header of this column.
The partial class generated by the EF.
[Table("Test")]
public partial class Test
{
[Key]
public long ID_Test { get; set; }
public long ID_TestStatus { get; set; }
//other properties
}
My Custom partial class:
public partial class Test
{
private static readonly TestRepository _testRepository;
static TestRepository()
{
_testRepository= new TestRepository();
}
public string StatusDescription
{
get { return _testRepository.GetStatusDescriptionById(ID_TestStatus); }
}
}
When i try to Sort using another column it works fine, but when i try to Sort using the custom property Column all the grid cell values gets empty, without any value.
Any suggestion?
It's not a very good idea to have data access code inside an entity. One reason is that it makes it very hard to write unit test. Another reason is that it is very likely to give rise to the n + 1 anti pattern. In your case, it does: one (1) query to get the Tests, then each Test (n) sends a separate query to the database to get its StatusDescription.
The way you implemented it also raises some eyebrows, because
_testRepository is static, which meas there is probable some context instance living for the entire lifecycle of the application - unless GetStatusDescriptionById creates a new context for each call, but that wouldn't be a good idea either.
The GetStatusDescriptionById call is made each time the property is accessed. In a web application this may not be a big problem because the objects are newly created each time they are requested anyway, but in other environments this could be highly inefficient.
A better approach would be to fetch the Testss with their Status included:
context.Tests.Include(t => t.TestStatus)
and have an unmapped property like
public string StatusDescription
{
get { return TestStatus== null ? string.Empty : TestStatus.Description; }
}
better still (in my opinion) would be not to show Test objects directly, but TestDto objects like
public class TestDto
{
public string StatusDescription { get; set; }
//other properties that match Test's properties
}
and use a tool like AutoMapper to map a collection of Tests to TestDtos. If Test has a property Status and TestStatus has a property Description, AutoMapper will be able to flatten that into StatusDescription automatically.
Both this StatusDescription property and the Dto appraoch set the state of a Test(Dto) object once. I don't think any grid component can mess with that.

View an Already Instantiated ViewModel in MVVMCross

Does anyone know how to view an existing IMvxViewModel?
In my app, I have already created a bunch of ViewModels (PhotoViewModel) inside of another view model. They exist as a property on the parent ViewModel (AlbumViewModel). It would be very nice to just show a particular instance of a PhotoViewModel instead of creating a new instance of that view model when I want to view it.
public class AlbumViewModel : MvxViewModel {
public ObservableCollection<PhotoViewModel> Photos
{
get { return GetValue(() => Photos); }
set { SetValue(value, () => Photos); }
}
}
public class PhotoViewModel : MvxViewModel { }
I was wondering if there was a way, other then creating my own IMvxViewModelLocator, to accomplish this task. I think having a protected method on the MvxNavigationObject called View could be really helpful both for new developers using the framework as well as performance. We'd be able to skip all of the reflection done currently to instantiate a view model.
The default ShowViewModel mechanism in MvvmCross uses page-based navigation - this navigation has to use Uris on WindowsPhone and Intents on Android.
Because of this, MvvmCross does not allow navigation by 'rich' objects - simple serialisable POCOs are Ok, but complicated 'rich' objects are not supported.
This is further essential because of 'tombstoning' - if your app/page/activity is later rehydrated then you cannot be sure of what historic View or ViewModel objects are actually in your history "back" stack.
If you want to navigate by rich object then the best way is to store those rich objects in a lookup service and to then navigate by some key/index into the lookup. However, I would personally call those lookedup objects Models rather than ViewModels (but the boundary does sometimes become blurred!)
Although based on MvvmCross v1 code, this question still gives quite a good background to this - What is the best way to pass objects to "navigated to" viewmodel in MVVMCross?
Some more up-to-date explanations include:
How to pass data across screens using mvvmcross
Custom types in Navigation parameters in v3
https://github.com/slodge/MvvmCross/wiki/ViewModel--to-ViewModel-navigation (under construction)
One final thing....
... the MvvmCross manifesto insists that MvvmCross is very open to customisation ...
Because of this you can override MvvmCross navigation and view model location if you want to. To do this, creating your own IMvxViewModelLocator would probably be a good way to start.
After some testing, below is a proposed solution. I'm not 100% in love with it, but it does work and provide the type developer experience I was looking for. So lets dig in.
To start, all of my ViewModels (VM) inherit from a base VM, AVM. This abstract base class supports looking up of an object as a public static method. It's a little gross, but it works well if you're willing to sip on the Kool-Aid. Below is the portion of the class that's relevant to this problem:
public abstract class AVM : MvxViewModel {
private static readonly Dictionary<Guid, WeakReference> ViewModelCache = new Dictionary<Guid, WeakReference>();
private static readonly string BUNDLE_PARAM_ID = #"AVM_ID";
private Guid AVM_ID = Guid.NewGuid();
private Type MyType;
protected AVM()
{
MyType = this.GetType();
ViewModelCache.Add(AVM_ID, new WeakReference(this));
}
public static bool TryLoadFromBundle(IMvxBundle bundle, out IMvxViewModel viewModel)
{
if (null != bundle && bundle.Data.ContainsKey(BUNDLE_PARAM_ID))
{
var id = Guid.Parse(bundle.Data[BUNDLE_PARAM_ID]);
viewModel = TryLoadFromCache(id);
return true;
}
viewModel = null;
return false;
}
private static IMvxViewModel TryLoadFromCache(Guid Id)
{
if (ViewModelCache.ContainsKey(Id))
{
try
{
var reference = ViewModelCache[Id];
if (reference.IsAlive)
return (IMvxViewModel)reference.Target;
}
catch (Exception exp) { Mvx.Trace(exp.Message); }
}
return null;
}
protected void View()
{
var param = new Dictionary<string, string>();
param.Add(BUNDLE_PARAM_ID, AVM_ID.ToString());
ShowViewModel(MyType, param);
}
In order to get this all wired up, you have to create a custom view model locator. Here's the custom locator:
public class AVMLocator : MvxDefaultViewModelLocator
{
public override bool TryLoad(Type viewModelType, IMvxBundle parameterValues, IMvxBundle savedState, out IMvxViewModel viewModel)
{
if (AVM.TryLoadFromBundle(parameterValues, out viewModel))
return true;
return base.TryLoad(viewModelType, parameterValues, savedState, out viewModel);
}
}
Lastly you have to wire up. To do so, go into your App.cs and override CreateDefaultViewModelLocator like so:
protected override IMvxViewModelLocator CreateDefaultViewModelLocator()
{
return new AVMLocator();
}
You're all set. Now in any of your derived ViewModels that are already alive and well, you can do the following:
myDerivedVM.View();
There's still some more I need to do (like making sure the WeakReferences do their job and I don't have memory leaks and some additional error handling), but at the very least it's the experience I was going for. The last thing I did was add the following command to the AVM base class:
public MvxCommand ViewCommand
{
get { return new MvxCommand(View); }
}
Now you can bind that command to any UI object and when invoked, it'll launch that view with that very instance of the VM.
Stuart, thanks for your help in steering me in the right direction. I'd be interested in hearing your feedback on the solution I provided. Thanks for all of your work with MVVMCross. It really is a very beautiful bit of code.
Cheers.

.Net MVC binding dynamic Type to a Model at runtime

I have a slightly long conceptual question I'm wondering if somebody could help me out with.
In MVC I've built a website which builds grids using kendoui's framework.
All the grids on my website are constructed exactly the same except for the model they use and the CRUD methods that need to be implemented for each model. I set things up where each Model implement an interface for CRUD methods like below to get the logic all in one place.
//Actual interface has variables getting passed
public interface IKendoModelInterface
{
void Save();
void Read();
void Delete();
}
public class Model1: IKendoModelInterface
{
[Key]
public int IdProperty1 { get; set; }
public int SomeProperty2 { get; set; }
public string SomeProperty3 { get; set; }
public void Save(){
//Implement Save
}
public void Read(){
//Implement Read
}
public void Delete(){
//Implement Delete
}
}
Then to speed up the writing of all the scaffolding Action methods needed to get the grids to work I created an abstract Controller that can call the interface methods of the Model that gets passed into it.
//Implement the AJAX methods called by the grid
public abstract class KendoGridImplController<T> : Controller where T : class, IKendoModelInterface
{
// Method called from kendo grid
public virtual ActionResult Create([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")]IEnumerable<T> createdRecords)
{
//Invoke Create Method for Model and return results
}
public virtual ActionResult Read([DataSourceRequest]DataSourceRequest request, int Id)
{
//Invoke read method for model and return results
}
//Update and Delete also implemented..
}
Then I just need a Controller per model that implements the abstract controller above passing in the type of Model being used.
public class ResponsibilityMatrixController : KendoGridImplController<Model1>
{
//Set up the page the grid will be on
public ActionResult Index(int id)
{
return View("SharedGridView", id);
}
//Can override abstract methods if needed but usually won't need to
}
I'm wondering if I can take this one step further or if I've reached the end of the road. To me it just seems like more repeated code if I have to create a controller per Model that does nothing but pass in the type to the abstract controller and calls the same View.
I attempted for quite a while yesterday to figure out if I could dynamically assign the type to the abstract controller. I setup something where I was sending back the type of model via strings and I could still invoke the methods needed. Where it failed, was that the mapping could no longer be done on any of the controller actions by default since the type isn't known at compile time. eg
public virtual ActionResult Create([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")]IEnumerable<T> createdRecords)
createdRecords can't be bound like this if T that's passed in is an interface and not the Model itself and I've found no real way to map the form data to an instance of a type that isn't known at compile time.
I'm wondering if there's an easy way to do this mapping between an instance of the type of object getting passed in that I can figure out at runtime, if there's some other way to set this up that I'm overlooking or if both those things are going to be way too much work and I should just not attempt something like this and build a controller per model like I do now?
In case anybody else finds this in the future here's what I've done so far to solve my issue. First I downloaded the impromptu-interface code lib which is incredibly helpful when dealing with dynamic types.
Then for the abstract controller's save methods where it was important that I could bind back to the original object type I did this.
// Method called from kendo grid
public virtual ActionResult Create([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")]IEnumerable<ExpandoObject> createdRecords)
{
Type originalGridType = GetTypeOfModelUsingCustomCodeIDevelopedEarlier();
foreach (ExpandoObject record in createdRecords)
{
var convertedType = Impromptu.InvokeConvert(record, originalGridType);
T objectInstance = Impromptu.ActLike(convertedType);
objectInstance.Save();
}
}
Then I just needed to add a cast in my model that could convert from the ExpandoObject to my model. An extra method that I still wish didn't have to be there but with some helper methods that I wrote it's not a lot more code to make happen.
public static implicit operator Model1(ExpandoObject expando)
{
Model1 model = new Model1();
//Set fields of model...
//....
return model;
}
From here everything works front to back. Maybe there's a better way but this is the best I could come up with so far.

Access to classes

I am not sure where/how to search for this question so I thought asking the comminuty of stackoverflow is the best bet.
Basically I am designing a Project which will simply provide a logic project access to a LINQ to SQL model to perform CRUD on a database. So within the Data project I have the LINQ to SQL model class and a C# class to provide access to the Model as shown below
public class Connection : IDisposable
{
private DataModelDataContext _model;
public DataModelDataContext model
{
get { return _model; }
set { throw new Exception("Object \"model\" is not allowed to be created outside of its container class", new NotSupportedException()); }
}
public Connection(string username, string password)
{
User u = _model.Users.Where(u => u.Username == username && u.password == u.Password);
if (u == null)
throw new ApplicationException("User credentials are invalid", new AuthenticationException());
_model = new DataModelDataContext();
}
public void refreshAndKeepChanges(object entity)
{
_model.Refresh(RefreshMode.OverwriteCurrentValues, entity);
}
public int getChangesCount()
{
return _model.GetChangeSet().Deletes.Count() + _model.GetChangeSet().Inserts.Count() + _model.GetChangeSet().Updates.Count();
}
public void Dispose()
{
_model.SubmitChanges();
_model.Dispose();
}
}
What I want is, when I compile the DLL is for the Logic project to have access to the Connection class (above) but not the DataModelDataContext (as this would defeat the object of passing user credentials).
My question is how can expose the Connection class (as public which I have already done) but hide LINQ to SQL data model from the DLL but allow the Connection class access to it???
using an extra namespace for the LINQ to SQL model does not work, i have found adding the DLL allows access to all the namespaces within the project.
Just change the model property to be internal, along with the DataModelDataContext class (which is probably done by editing the DBML, either in the designer or by hand). It's fine for the Connection class to know about internal classes - it just can't expose them publicly.
As a couple of asides:
If the model setter is never going to be functional, why have it at all? Just get rid of it.
You should start following the .NET naming conventions
You change public DataModelDataContext model to either
internal DataModelDataContext model
if you want it to be "public within that assembly, but private to all other assemblies"
protected DataModelDataContext model
or
private DataModelDataContext model
if you don't want to expose DataModelDataContext to other classes in that assembly.
Most likely you want it as internal.
The term you can search for (or read more directly on MSDN) is Access Modifiers.

Categories