Silverlight POCO returned by RIA services - c#

I am using a Silverlight 5 Business Application using RIA services to return a POCO class from the service side to populate a hierarchical menu.
The original problem I had with the POCO class was that the SubMenuItems property was not getting passed over RIA services although it was populated on the service side.
Original POCO
public class BusinessModelMenuDto
{
[Key]
[Required]
public int ID { get; set; }
public string TextToDisplay { get; set; }
public string ImageSource { get; set; }
public IEnumerable<BusinessModelMenuDto> SubMenuItems { get; set; }
}
Service call
public IEnumerable<BusinessModelMenuDto> GetCabsHeirarchy()
Following some further investigation I found that the [Include] and [Association] attributes were required on the SubMenuItems to pass the data over. Doing this the first time with the Association of ID => ID did not give the desired results so I added the ParentID property and changed my loading code to populate the Foreign Key as below. I also changed the Associate to map from ID to Parent ID.
Updated POCO class
public class BusinessModelMenuDto
{
[Key]
[Required]
public int ID { get; set; }
public int? ParentID { get; set; }
public string TextToDisplay { get; set; }
public string ImageSource { get; set; }
[Include]
[Association("SubItems", "ID", "ParentID")]
public IEnumerable<BusinessModelMenuDto> SubMenuItems { get; set; }
}
On the server side I am loading two levels of the menu at the moment so the top level item contains a collection of SubItems but there are no further SubItems below that.
The problem I have is that when RIA services sends the collection over the wire the hierarchy is being jumbled. I have confirmed that what I am returned is correctly structured but it does not arrive on the client side correctly. The top level is OK but the second level (SubMenuItems) is mixed up and two furter SubMenuItems levels have appeared.
Any idea what I am doing wrong? I assume that the problem is with the Association or the fact that the same POCO object (BusinessModelMenuDto) is being used for the multiple levels.

We found we had to use Guids for the item Key and assign a unique value to it on the server before passing back to the client.
So your class definition would become:
public class BusinessModelMenuDto
{
[Key]
[Required]
public Guid ID { get; set; }
public Guid? ParentID { get; set; }
public string TextToDisplay { get; set; }
public string ImageSource { get; set; }
[Include]
[Association("SubItems", "ID", "ParentID")]
public IEnumerable<BusinessModelMenuDto> SubMenuItems { get; set; }
}
Then when you create a new element set the ID:
ID = Guid.NewGuid();

Related

Mapster - Dynamic property selection or ignore

I have a business need to dynamically select ONLY the properties of a given model that are specified, similar to an OData select clause. I am currently using Mapster's ProjectToType functionality to populate view models from EF Core entities.
Is there any way to tell Mapster to only select a given list of properties in the query that it generates? Or a way to take the full model mapping, and change mappings at runtime in an instance of TypeAdapterConfig to ignore properties that aren't in a given list of properties?
The end solution needs to be generic and work with navigation properties, because it will be applied to all of our entities in the database. We also used DynamicLinq in some cases, not sure if that can be used on top of Mapsters ProjectToType functionality.
Example:
Entities (Some properties omitted for length):
namespace DataAccess.Entities
{
public class Series
{
public Guid Id { get; set; }
public string Description { get; set; }
public long? StackRank { get; set; }
public string EntityId { get; set; }
// Other properties
}
public class Model
{
public Guid Id { get; set; }
public string Description { get; set; }
public string EntityId { get; set; }
public long? StackRank { get; set; }
public Guid SeriesId { get; set; }
public virtual Series Series { get; set; }
// Other properties
}
}
View Models (Some properties omitted for length):
namespace Models
{
public class Model
{
public Guid Id { get; set; }
public string Description { get; set; }
public string EntityId { get; set; }
public long? StackRank { get; set; }
public Guid SeriesId { get; set; }
public virtual Series Series { get; set; }
// Other properties
}
public class Series
{
public Guid Id { get; set; }
public string Description { get; set; }
public long? StackRank { get; set; }
public string EntityId { get; set; }
// Other properties
}
}
Given a rest call to get a list of all Model view models, with this list of properties to include:
var properties = new List<string> {
"Id",
"EntityId"
"Description",
"Series.Id",
"Series.Description",
"Series.EntityId"
}
The results would return some type of dictionary, dynamic, or anonymous object that contained ONLY these properties, and the other properties would not even be included in the final select of the SQL query that gets created.
In the end, I decided to use Arca Artem's suggestion, with a little twist. I used reflection to grab a list of all properties of the model and cache them. After that, I compared the cached properties vs the list of properties to include, and ignored the properties that weren't in both lists. Kinda like this:
var clonedConfig = mapsterInstance.Clone();
clonedConfig.ForType<TSource, TDestination>().Ignore(propertiesToIgnore);
var models = await query.ProjectToType<TDestination>(clonedConfig).ToListAsync();
Maybe not the most elegant solution, but it worked well enough for what I needed. I also set up our json serializer to ignore null values.

Entity Framework Code First One to One Cascade Deletes

Have and "Address" model used by several other models ("Employee" & "Client").
I would call this a one to one relationship, I could be wrong. The address is required by both of the other models. Remove, deletes only the parent object.
Tried in both EF Core and EF6. Remove deletes the parent object, but not the "Address" object.
public class Address
{
public int AddressID { get; set; }
public string Street { get; set; }
public string CityStateZip { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
[Required]
public virtual Address EmployeeAddress { get; set; }
}
public class Client
{
public int Id { get; set; }
public string Name { get; set; }
[Required]
public virtual Address ClientAddress { get; set; }
}
No error messages - context.remove simply won't delete the child object. Complete noob here when it comes to EF. Sorry, this is probably a very basic question, but please believe that I have searched extensively. Most solutions suggest a foreign key back to the parent - but, in this case, the child object can be used (but not shared) in several different models.
The same Address object can be used in multiple Employee and/or Client instances as currently implemented.
The suggestion you received
Most solutions suggest a foreign key back to the parent - but, in this case, the child object can be used (but not shared) in several different models.
informs Entity Framework that a given Address can only appear in one specific Employee/Client.
You should be able to resolve this by having Employee and Client inherit from a common base class, e.g.
public class Person
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
[Required]
public virtual Address PersonAddress { get; set; }
}
public class Employee : Person
{
// Other properties that make Employee unique go here
}
public class Client : Person
{
// Other properties that make Client unique go here
}
Then add the backreference to the base class
public class Address
{
public virtual int AddressID { get; set; }
public virtual string Street { get; set; }
public virtual string CityStateZip { get; set; }
[Required]
public virtual Person AddressOf { get; set; }
}

Modeling a one-to many relationship- Model vs ViewModel

I am currently trying to model an object class with a one-to-many relationship with another object in Model-First MVC- a "Contact" object that includes, among other things, a list of (references to?) one or more "Interests", chosen upon creation of a Contact from the full database list of Interests. It is my understanding that one uses a ViewModel to accommodate such a relationship, but I think I am misunderstanding what does or does not go in the model vs the viewModel.
At present, I have a Contacts model:
public class Contact
{
public int Id { get; set; }
public string Email { get; set; }
public virtual List<Interest> Interests { get; set; }
public List<int> InterestIds { get; set; }
}
An Interest model:
public class Interest
{
public int Id { get; set; }
public string Name { get; set; }
}
A Contact viewModel:
public class ContactViewModel
{
public int Id { get; set; }
public string Email { get; set; }
public List<int> InterestIds { get; set; }
public List<InterestViewModel> Interests { get; set; }
}
And an Interest viewModel
public class ContactViewModel
{
public int Id { get; set; }
public string Email { get; set; }
public List<int> InterestIds { get; set; }
public List<InterestViewModel> Interests { get; set; }
}
But I'm getting conflicted accounts of what goes where.
In short, I intend the end result that I should be able to choose one or more Interests (preferably with a series of checkboxes) from the Create view to be stored in the new Contact, and then from the Index view be able to filter the table of Contacts by which Interests they do or do not have. I have logic planned out for most of that already, but for the time being how should I design my Models vs my ViewModels in order to best accommodate this vision?
your Contact entity has a logical error, you should remove InterestIds property from Contact entity and add a property with name ContactId to your Interest entity. it provides foreign key for contact(one to many relation from Contact to Interest). however if ViewModel is equals to the Model, so you don't need any ViewModel.

Using Data annotations to create navigation property from class to itself?

Using Entity Framework Code first I have a class that holds data for a drop-down list. The same class holds records that are sub-items for the items in the main list. Ultimately this will create a cascading set of drop-down lists.
I am trying to figure out how to make the navigation property for the class link back to itself. The issue class is the one that I am using to populate the drop-down list. The Complaint class also has a link to the Issues class but does not need a link back to the subcategory.
public class Issue
{
public Issue()
{
Complaints = new List<Complaint>();
SubIssues = new List<Issue>();
}
[Key]
public int IssueID { get; set; }
public string Name { get; set; }
public bool IsSubCategory { get; set; }
[ForeignKey("IssueID")]
public ICollection<Issue> SubIssues { get; set; }
public virtual ICollection<Complaint> Complaints { get; set; }
}
public class Complaint
{
public Complaint()
{
}
public int ComplaintID { get; set; }
public string Name {get; set;}
[ForeignKey("IssueID")]
public virtual Issue Issue { get; set; }
}
I did something similar, but actually did only have a parent reference in the children. Either way this should work.
public class Folder
{
[Key]
public int Id { get; set; }
// Some Property
public string Name { get; set; }
// They foreignkey for Many-side
public virtual Folder Parent { get; set; }
// The list for One-side (Not tested in my application)
public virtual ICollection<Folder> SubFolders { get; set; }
}
It is same as a regular one-to-many relation, just all the references are within same entity.

Stopping a field change being recorded as a modification to a POCO object

I am developing with silverlight, and RIA services. I have a POCO object defined on the server side like this,
public class AssessmentRoad
{
[Key]
public int Id { get; set; }
[Required]
public int RoadLength { get; set; }
public int RoadId { get; set; }
[Required]
public string RoadName { get; set; }
[Required]
public string Suburb { get; set; }
public bool HasModified { get; set; }
}
The field HasModified is calculated and used on the client side only.
RIA services when I call SaveChanges decides that the entities need saving because the HasModified field has changed.
Is there an attribute I can use to make sure this doesn't happen? Or do I need to use a partial class etc?
On second thoughts perhaps the HasModified field shouldn't be there at all, and this should be wrapped up in a ViewModel instead?
Add this property to a client-side partial class. See http://msdn.microsoft.com/en-us/library/ee707331(v=VS.91).aspx.

Categories