How to keep custom navigation properties after a model rebuild? - c#

I have several navigation properties from a 'Users' table to a 'Reports' table. The navigation properties that are generated are obviously accessed like this:
USER.REPORTs.Where(x => ...)
USER.REPORTs2.Where(x => ...)
USER.REPORTs3.Where(x => ...)
The first one is user createdId, second UserApprovedId etc... basic stuff.
These are extremely difficult to interpret. Its difficult to tell which property you are navigating without accessing the EDMX and checking the navigation property.
Now I know I can create my own End1/End2 navigation properties the properties manager but these are lost if the Model is recreated.
Is there a way around this?

I have not tried this, but here's an idea: since all the entity types are partial classes why not wrap the navigation property generated by Visual Studio in another property with a convenient name?
In your designer file you'll have something like this:
public partial class MyEntity : EntityObject
{
#region Navigation Properties
public EntityCollection<MyOtherEntity> Other_Entities1
{
// ...
}
#endregion
}
You can then create another file in which to wrap the navigation property:
public partial class MyEntity
{
public EntityCollection<MyOtherEntity> OtherEntities
{
get { return Other_Entities1;}
}
}
You'll use the property above throughout your code and since the same logic is used when Visual Studio generates the .edmx file the wrapped property won't change.
Even if the wrapped property will change its name you'll need to adjust the code in a single place.

I'm not sure if I'm understanding your problem correctly, but it sounds like you just want a "cleaner" way to access the results of a REPORTs.Where(...) LINQ query directly from the USER object. If that is the case, I suggest creating extensions of the USER object like this:
public static class UserExtensions
{
public static List<REPORT> ReportsWithSomeCondition(this USER user)
{
return user.REPORTs.Where(...).ToList();
}
}
And the way you can cleanly call this is:
List<REPORT> results = USER.ReportsWithSomeCondition()
If I totally missed the point, please clarify your question and I will delete this answer.

I think i have the same problem as i understand from your question.
You want to keep your navigational properties names as clear as you can but whenever recreate your Model from edmx ?!.
Actually i hope if there is a better solution but here what I'm doing :
Name your relations in DataBase a good names like : FK_Users_CreateUserReport, FK_Users_ApprovedUserReport ... or any suitable names we'll then rename the navigational properties as ApprovedUserReport and CreateUserReport so on ...
make a helper code to execute whenever you recreate your Model and this code will open your edmx file and makes update to all navigational properties you want something like this:
// file here is the path to your edmx file
if (!string.IsNullOrEmpty(file))
{
var ns = XNamespace.Get("http://schemas.microsoft.com/ado/2008/09/edm");
var doc = XDocument.Load(file);
var list = (from xElem in doc.Descendants(ns + "NavigationProperty")
where xElem.Attribute("Name").Value.StartsWith("REPORTs"))
select xElem).ToList();
foreach (var item in list)
{
var newName = item.Attribute("Relationship").Value.Split('_').LastOrDefault();
if (!newName.Contains("."))
item.SetAttributeValue("Name", newName);
else
{
var ss = newName.Split('.').LastOrDefault();
}
}
doc.Save(file);
MessageBox.Show(list.Count.ToString());
}
Final thing if you used Code Only pattern then this problem is gone but in that case you should keep your Model in agreement with your DataBase by hand.

You have to put all your custom entity code in separate code files using the partial class mechanism. This allows the generated code to be generated without your custom code to be affected.

Wahid's answer seems to be the best one for long term maintenance. We considered implementing interface properties in the Partial Class we use as a "Buddy Class" for extensions and setting up Metadata linking. But then the properties in the T4 template we are Interfacing would still be public and they should be private.
To improve upon Wahid's suggestion; we chose to instead of changing the standard of how we name Foreign key relationships, extend them.
FK_Users_Report_CreateUserReport would actually be our solution. The standard naming convention for the first 2 values is maintained and in the update model code you can force it to only change the navigation property names of ones with the 3rd underscore and 3rd value on it. Ensuring you do no effect anyone other navigation property names if they didn't follow the standard naming convention for Foreign Keys in the DB.

Related

MVC data annotations

I'm using entity framework. It auto generated an Answer class. But I cannot modify this class as it will be overwritten if code is regenerated.
Is there a way/technique to add data annotations using this class?
The reason I ask is that I have a Create Answer view that uses the Answer class. Hence, I want to add data annotations such as Required, etc.
If I cannot add data annotations to the Answer class, then I have to create an "AnswerDuplicate" class, pass that into the view, and also use that in my Create() method. However, I then have to map all the values from AnswerDuplicate to an instance of Answer, since Answer is what I "add" to the entity.
Seems like extra work since Answer is autocreated (class and the binding in Create() method). Would be nice if I can just add data annotations.
If this is not possible, then is my only option to create an "AnswerDuplicate" class and use that in place of the Answer class?
My suggestion is: Use ViewModels.
I always consider creating a ViewModel when editing/viewing data - rather than passing the model object directly down to the view.
How Will This Help?
The logic to display it in the view (with Required, DataType and validation such like) can be left down to the ViewModel; while your Model is just left as a normal all-intents-and-purposes class (in your case, a generated one).
As an example, you could have an AnswerViewModel, which contains all of your display/validation logic, to then use in your corresponding View.
How Do I Save Time Mapping Properties?
You can use AutoMapper (or other similar auto-mapping packages) to then automatically map the properties between your model and the view model, for easy updating of entities etc.
This then saves you time having to write lines-upon-lines of code to update entities - which may essentially need to change over time - this can be a big problem (and a huge PITA) if refactoring/adding extra properties across different classes.
How Does This Help Going Forward?
Well, because you are not leaving the logic up to your class:
Let's say you have 3 different views for different purposes (Add, Edit, Delete)
If (for some reason) you need to show/display something differently in only one particular view, you are able to just apply/change the logic in the relevant ViewModel; rather than worrying about updating the Model and having breaking changes affect everything else.
Here is a handy tutorial on How To Use ViewModels In MVC: http://rachelappel.com/use-viewmodels-to-manage-data-amp-organize-code-in-asp-net-mvc-applications/
I do hope this helps, somewhat :)
If you need me to provide any examples - just let me know.
I think the best solution is to use ViewModels as #Geoff James said, but if you don't like to add different classed you can write a partial class and add the MetadataType attribute to it and the add the attributes you want like Required to its properties.
public partial class Answer // this is auto-generated
{
public long AnswerID {set; get;}
}
[MetadataType(typeof(Answer ))]
public partial class Answer // this is what you can write
{
[Required]
public long AnswerID {set; get;}
}
remember that both class must have a same namespace.
And other solution to your problem is the you can switch to Code First

Asp.net C# model object binding

The product have some fields that can not be changed,
so I want to bind the object with only selected field.
For now I'm doing this(below) way (like binding manually), but I believe there is better and clean way. How to binding Model object to model object with only selected fields?
[HttpPut]
public JsonResult update(Product editedProduct) {
Product originalProduct = unitOfWork.ProductRepository.Get(filter: q => q.no == editedProduct.no).Single();
originalProduct.name = editedProduct.name;
originalProduct.modelNo = editedProduct.modelNo;
originalProduct.size = editedProduct.size;
originalProduct.color = editedProduct.color;
originalProduct.description = editedProduct.description;
originalProduct.price = editedProduct.price;
//originalProduct.upc = editedProduct.upc; //UPC can not be changed
//originalProduct.sku = editedProduct.sku; //SKU can not be changed
unitOfWork.Save();
return Json(new { success = true });
}
please advise me,
In my opinion there is absolutely nothing wrong with this approach. It is possible to do some things differently but it does not mean it is better.
Create a DTO/ViewModel class to represent the class you accept and return from the service. This way you can have different shapes of the data if you need it. For example you can skip a security critical field. I think this will be an improvement.
Use a framework like AutoMapper to do the mapping between the objects. This is quite popular approach but I personally prefer explicitly copying the fields.
You can update the object without retrieving it. I assume you are using Entity Framework. You can refer to this question for details - How to update a record without selecting that record again in ADO.NET Entity Framework? . I personally don't think that this will improve your code. I think you should do it only if you have performance issues with your current approach.
You can put the mapping code in your repository in an Update method or something.
BTW it seems like your repository is currently useless. You are just writing a wrapper around your ORM which makes the code more complex and more buggy. Repository is an anti-pattern when you are using an ORM. Your ORM is the repository.
Well, don't do it.
For this case you should create a separate ViewModel with only necessary fields.
I would not expose the setter in the class for example.
public class Product{
public string upc {get;}
}
This will not allow the property to be set.

Bare-bones shallow serialization of ado.net entity

I realize there are loads of questions already posted regarding serialization of ADO.Net entities, but I haven't had any luck finding one that really addresses quite what I want to do.
Basically, I need a really bare-bones, shallow JSON or plain-object representation of an ADO.Net entity. The purpose is for change-logging; i.e. when a record is going to be changed, I want to snag a copy of its data "before" and "after", and log the change.
I don't want any of the navigation, complex or other properties to be considered; just the scalar properties of the entity. If I miss some data that only would appear in special cases, that's fine -- just trying to do a rough log. Ideally my final code should look something like this:
Employee emp = db.Employees.First();
string oldRecordJSON = MySerializer.serialize(emp);
emp.Name = "Fred";
db.saveChanges();
string newRecordJSON = MySerializer.serialize(emp);
ChangeLog.logDBChange("Employees", emp.ID, oldRecordJSON, newRecordJSON, DateTime.Now);
...Any quick & easy way to implement MySerializer.serialize?
Thanks!
If you're just wanting some specific properties of your employee, consider creating a basic model and serialising that.
var serializer = new JavaScriptSerializer();
serializer.Serialize(new MyEmployeeModel{ // set fields here});
You can build this as a converter if you wish, that's how I'd do it.
I have an interface, IConverter<TInputType, TOutputType> from which you can create a converter to inject (or whatever you want to do) into your code.
public interface IEmployeeFromDatabaseToBasicEmployeeModelConverter
: IConverter<TheDBType, MyEmployeeModel>{}
public class EmployeeFromDatabaseToBasicEmployeeModelConverter :
IEmployeeFromDatabaseToBasicEmployeeModelConverter
{
public MyEmployeeModel Invoke(TheDBType myDbTypeObject)
{
return new MyEmployeeModel{
// set properties.
}
}
}

How to create custom get and set methods for Linq2SQL object

I have some objects which have been created automatically by linq2SQL.
I would like to write some code which should be run whenever the properties on these objects are read or changed.
Can I use typical get { //code } and set {//code } in my partial class file to add this functionality? Currently I get an error about this member already being defined.
This all makes sense.
Is it correct that I will have to create a method to function as the entry point for this functionality, as I cannot redefine the get and set methods for this property.
I was hoping to just update the get and set, as this would mean I wouldn't have to change all the reference points in my app. But I think I may just have to update it everywhere.
Not sure about read, but you could track changes of your objects. E.g. there is PropertyChangedEventHandler on auto generated entities.
So what have you do is to white a partial class (let's assuming you have a Person entity):
public partial class Person
{
public Person()
{
this.PropertyChanged +=
new PropertyChangedEventHandler(Person_PropertyChanged);
}
protected void Person_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
// your code here
}
}
What I did when I wanted to do this was make the property private/inaccessible (since this can be done as part of the DBML definition without editing the generated code), and give it a different name than the property I want to expose. Then I implemented a public wrapper property in a partial class, using the name I wanted to expose. Then (if you want to be really fancy) implement a LINQ provider that can convert queries that refer to the wrapper properties to queries that refer to the underlying properties. I have done all this and it's been working well, but the custom LINQ provider was tricky.
Unless you modify the generated code that was made, and then add additional code to the setter (such as using the pattern like in WPF, with INotifyPropertyChanged), then this would be impossible.

ASP.Net MVC multiple inheritance in a View

I'm trying to figure out if its possible to have multiple inheritance in a view in ASP.Net MVC. Right now I'm trying to print out a list of entries from two different tables from my model in a single View. I have the following line at the top of my view:
Inherits="System.Web.Mvc.ViewPage<List<GEApproval.Models.CoursePrefix>>"
But I also want to include the table Course as follows:
Inherits="System.Web.Mvc.ViewPage<List<GEApproval.Models.Course>>"
I'm not sure how this can be accomplished, any help or suggestions are appreciated.
UPDATE:
Thank you all for your help, I went ahead and created a composite class as follows:
namespace GEApproval.Models
{
public class Listings: GEApproval.Models.CoursePrefix, GEApproval.Models.ICourse
{
public List<CoursePrefix> CoursePrefixObjList { get; set; }
public List<Course> CourseObjList { get; set; }
private GEApprovalDataModel _db;
//Constructor
public Listings()
{
_db = new GEApprovalDataModel();
}
//Generate a list of all courses associated with the prefix and place in ViewData model
public void listCourses(ViewDataDictionary viewData, int prefixID)
{
var test = _db.CoursePrefix.Include("Course").First(cp => cp.id == 1);
//Show total courses for this prefix
viewData.Model = test.Course.ToList();
viewData["prefix"] = test.Prefix;
viewData["courseCount"] = test.Course.Count;
int courseCount = test.Course.Count();//Test
}
}
}
And in my view, I now have the following line:
Inherits="System.Web.Mvc.ViewPage<List<GEApproval.Models.Listings>>"
I'm still a little confused because I still cannot access the properties of the Course object when listing them in my view, because I'm only inheriting directly from CoursePrefix. I'm not sure what I'm missing. Do I need to have a constructor for the composite object? Do I need the inherit and implementation statements for CoursePrefix and ICourse respectively if I'm already, supposedly, exposing the properties of each within the Listings wrapper class??
Create a ViewModel class that has properties that expose both sets of data. Bind to that instead.
You model can only contain one object. If you have multiple objects you need for your view you will have to create a composite object.
This can be as simple as exposing multiple properties that match the object types needed in the view.
public class ModelObj
{
public List<CoursePrefix> CoursePrefixObjList {get; set;}
public List<Course> CourseObjList {get; set;}
}
Then just use your ModelObj in the view
Inherits="System.Web.Mvc.ViewPage<ModelObj>"
This is not inheritance, it's generics, very differant.
No it isn't possible, you need to combine them into a wrapper class containing two references, or simply adding a reference to CoursePrefix within the Course class would seem reasonable, but i base that on a very very limited understanding of your model!
There is no such thing as multiple inheritance in .Net. As the other answers have mentioned, use a composite ViewModel object for this situation (this is generally considered a much better design choice, even in languages that support it).
If both of them are derived from a common type you could have your view be of that type. Then you may need to check the type in a few places and output the type specific properties after casting, while outputting all the common properties normally. The down side is that the View may be considered too smart in this case.
If these are really separate types, you should create two different Views, seems the more object oriented way to go.
You could create a composite View of these two types. I'd be against it, as one of them might always be null.
The real question is why you're trying to print out two different tables in the same View. If both of these tables are always filled then go for it and create the composite DTO, otherwise these seem like separate Views / one View of a common base.

Categories

Resources