MVVM subproperty change detection - mvvm

My problem is as follows:
I am working with MVVM pattern and I would like to know how to detect changes of subproperties.
I have a textbox:
<TextBox Name="Descripcion" Text="{Binding AccionActual.Descripcion,Mode=TwoWay}" />
In the ViewModel I have the property:
Accion _accionActual;
public Accion AccionActual
{
get { return _accionActual; }
set
{
_accionActual = value;
RaisePropertyChanged("AccionActual");
}
}
The Accion entity definition is:
public partial class Accion : Entity
{
public Accion()
{
this.AccionesDocumentos = new HashSet<AccionDocumento>();
}
public int IdAccion { get; set; }
public int IdEmpleado { get; set; }
public string Descripcion { get; set; }
public string DescripcionDetalle { get; set; }
public bool Finalizada { get; set; }
public Nullable<int> IdExpediente { get; set; }
public Nullable<int> IdOrdenTrabajo { get; set; }
public bool Facturable { get; set; }
public Nullable<short> GestComAlbaranAƱo { get; set; }
public Nullable<short> GestComAlbaranEmpresa { get; set; }
public Nullable<int> GestComAlbaranNumero { get; set; }
public bool Facturado { get; set; }
public bool ComputarHorasACliente { get; set; }
public string DescripcionInterna { get; set; }
public virtual Aplicacion Aplicacione { get; set; }
public virtual AplicacionModulo AplicacionesModulo { get; set; }
public virtual Cliente Cliente { get; set; }
public virtual ClienteContacto ClientesContacto { get; set; }
public virtual Empleado Empleado { get; set; }
public virtual Expediente Expediente { get; set; }
public virtual OrdenTrabajo OrdenesTrabajo { get; set; }
public virtual ICollection<AccionDocumento> AccionesDocumentos { get; set; }
}
I could create in the ViewModel a property for each of the properties of Accion, but there any way to receive the changes without having to create a property for each of the properties of Accion?

You have two choices- either modify the Accion class to implement INotifyPropertyChanged or create a ViewModel wrapper to do it.
Where you put this is up to you- do what works best for you. There is a question on the merits of doing it in the ViewModel vs Model class here.
You could take out the manual process of doing this by looking into something like notifypropertyweaver- try using Google to look for INotifyPropertyChanged Aspect Oriented Programming. There is a Stackoverflow question on it here.

This kind of redundant double wrapping by the ViewModel is a common problem in classic MVVM and drives me nuts too.
You have several options:
Have your entity implement INotifyPropertyChanged and expose the Entity to the View the way you did it with the AccionActual property.
Hide your Entity completely behind a corresponding ViewModel object, and add only those properties to the ViewModel that you actually need in the View. Introduce a clever change notification infrastructure that notifies your ViewModel about changes in the Model and raise PropertyChanged in your ViewModel accordingly. This "change notifcation infrastructure" could be an EventAggregator and maybe you can get away with some sort of bulk/meta update (e.g. raise NotifyPropertyChanged for all relevant properties in the ViewModel when you received the event "the entity changed".

Related

The entity type 'Program' requires a primary key to be defined

I am trying to make a simple website that tracks students, programs, and classes. I've created the entities and I'm getting an error when trying to add the migration.
"The entity type 'Program' requires a primary key to be defined."
I have tried using the [Key] attribute and there is an Id field. The other table was created just fine. What else should I try?
Here is the problem class:
public class Program
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool UseRanks { get; set; }
}
Here is another table that I had no problems creating a migration for:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string CellPhone { get; set; }
public string HomePhone { get; set; }
public string WorkPhone { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public DateTime BirthDate { get; set; }
}
Here is what is in my ApplicationDbContext class:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
//public DbSet<Attendance> Attendances { get; set; }
public DbSet<Person> People { get; set; }
public DbSet<Bill> Bills { get; set; }
//public DbSet<Session> Sessions { get; set; }
public DbSet<Program> Programs { get; set; }
}
I've commented out the other entities because I was trying to add them one at a time. Trying to add a migration with all the entities resulted in the same error with the same specific class.
Complete shot in the dark, but based on the name of this class, I'm guessing you're referencing the wrong Program. Make sure that your DbSet<Program> is actually using your Program entity and not something like the Program class used at the console app level. You'll likely need to explicitly use the namespace, i.e. DbSet<MyApp.Models.Program>.
You might also consider changing the name of the class to remove any chance of ambiguity. There's some class names that are just going to wreck havoc trying to use them because they'll conflict with framework stuff constantly. It's usually more hassle than it's worth just to have that particular name. Program is one of those.
You can try to use this way:
public class Program
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool UseRanks { get; set; }
}
Adding [Key] attribute to the Id property.
In the file ApplicationDbContext.cs, you can override OnModelCreating method:
public DbSet<Program> Programs { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Program>().ToTable("Programs").HasKey(x => x.Id);
}

Incorrect Domain model with ef

I have a little problem with Entity Framework when trying to model the real life
problem.
I have 2 entity like this :
public class Person
{
public int Id { get; set; }
public ICollection<Task> Tasks{ get; set; }
}
public class Task
{
public int Id { get; set; }
public Person Assignee{ get; set; }
public Person Assigner{ get; set; }
}
but if I want to use Entity framework,it forces me to change my model like this that it is different from real life !!
public class Person
{
public int Id { get; set; }
public ICollection<Task> AssigneesTasks{ get; set; }
public ICollection<Task> AssignerTasks{ get; set; }
}
(i just have single one-to-many relation in fact)
what is the solution to keep my model according to real life model?
Well you might want to know what tasks a person has assigned to them, and what tasks they have assigned to others. If you don't want both Navigation properties you don't need them in EF. But you do need to tell EF which relationship the Navigation Property is for. EG:
public class Person
{
public int Id { get; set; }
[InverseProperty("Assignee")]
public ICollection<Task> Tasks { get; set; }
}
public class Task
{
public int Id { get; set; }
public Person Assignee { get; set; }
public Person Assigner { get; set; }
}

Map many to many objects using Entity Framework

For example we have profile and organisation. Both have articles.
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
}
public class Profile
{
public int Id { get; set; }
public string Email { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
public class Organisation
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
In this way Article should have two kinds of parent so it should have something like parent type to be able to access a parent when you select articles directly.
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
public int ParentId { get; set; }
public ArticleParentType Parent { get; set; }
}
Is it possible to map it using Entity Framework?
Is it a good idea to do it?
What is the best practice for storing this kind of data?
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
public int ParentId { get; set; }
public ArticleParentType Parent { get; set; }
}
Is it possible to map it using Entity Framework?
Is it a good idea to do it?
Possible yes but not a good idea. The underlying Database can't use a foreign key for Parentid. It would be slow.
What is the best practice for storing this kind of data?
A simple approach, with 2 Nullable parents and without CascadeOnDelete:
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
public virtual Profile Profile { get; set; }
public virtual Organisation Organisation { get; set; }
}
Alternatively you could use inheritance for Article, ie class OrganisationArticle : Article {}

Representing Graph in EF Code-First

I am trying to represent a graph with typed edges in an entity-framework code-first model. I am having quite a difficulty understanding how to set up the relationships correctly. I am calling the nodes in my graph 'Items' and the edges 'Relationships' Here is what I have:
public class Item : Learnable
{
public Boolean IsBeginningItem { get; set; }
public virtual List<Relationship> RelationshipsLeft { get; set; }
public virtual List<Relationship> RelationshipsRight { get; set; }
}
-
public class Relationship : Learnable
{
public Boolean IsPrerequisiteRelationship { get; set; }
public virtual RelationshipType RelationshipType { get; set; }
public int ItemLeftID { get; set; }
[ForeignKey("ItemLeftID")]
public virtual Item ItemLeft { get; set; }
public int ItemRightID { get; set; }
[ForeignKey("ItemRightID")]
public virtual Item ItemRight { get; set; }
}
And here is what I am getting:
How can I get the RelationshipsRight property of Item to correspond to the ItemLeft property of Relationship AND the RelationshipsLeft property of Item to correspond to the ItemRight property of Relationship?
Oh... and I guess I should explain that this is supposed to be a directed graph that I can navigate bidirectionally. :)
You can use the [InverseProperty] attribute to bind the correct pairs of navigation properties together:
public class Relationship
{
//...
public int ItemLeftID { get; set; }
[ForeignKey("ItemLeftID"), InverseProperty("RelationshipsRight")]
public virtual Item ItemLeft { get; set; }
public int ItemRightID { get; set; }
[ForeignKey("ItemRightID"), InverseProperty("RelationshipsLeft")]
public virtual Item ItemRight { get; set; }
}

Entity framework Database First & EF Code First get Relation Object By ID

in EF Database First when change ForeignKey(CommodityGroupID) automatic Get CommodityGroup for Commodity object, But in EF Code First(4.3.1) not doing.
public class Commodity
{
public int CommodityID { get; set; }
public string MadeBy { get; set; }
public decimal ServiceTimePrice { get; set; }
public decimal QCPrice { get; set; }
public int ServicePoint { get; set; }
public string Note { get; set; }
public int CommodityGroupID { get; set; }
[ForeignKey("CommodityGroupID")]
public virtual CommodityGroup CommodityGroup { get; set; }
}
public class CommodityGroup
{
public int CommodityGroupID { get; set; }
public string CommodityGroupName { get; set; }
public virtual ICollection<Commodity> Commodities { get; set; }
}
this Property defined in Edmx file (database first), i Should define this code in ef code first?
[BrowsableAttribute(false)]
[DataMemberAttribute()]
public EntityReference<CommodityGroup> CommodityGroupReference
{
get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<CommodityGroup>("GaamRepairModel.FK_Commodity_CommodityGroup", "CommodityGroup");
}
set
{
if ((value != null))
{
((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedReference<CommodityGroup>("GaamRepairModel.FK_Commodity_CommodityGroup", "CommodityGroup", value);
}
}
}
It sounds like you're wanting a change tracking proxy. You want the CommodityGroup navigation property to update automatically when the FK is changed correct?
See this post on MSDN for details about the change tracking proxy.
This post on MSDN shows some code on how to test of your proxy object is being created properly.
Is this a new object? If so, you'll need to call the CreateObject function on your DbSet, not use the New Commodity().