I have a model that looks like this:
// Subclass 1
class A
{
public B PropB { get; set; }
}
// Subclass 2
class B
{
public List<A> PropA { get; set; }
}
// And finally Model
class Model
{
public List<A> PropA { get; set; }
public List<B> PropB { get; set; }
}
Lists A and B inside Model class have references to some elements of each other.
How should the proper ViewModel look like in this case?
If there were no cross-references, that would be just 2 ObservableCollections of sub-ViewModels, but I cannot manage the situation with the references. Should each sub-ViewModel contain a references to other sub-ViewModels?
Hope that's clear enough.
You might want to have a look at Catel. It allows you to lazy-load view models based on a model. This way, you can create endless chains of view models without having to specify them first.
So, when a view detects a specific model, it will automatically convert it into a view model and you are good to go. For more information, read the docs about the nested user controls problem.
Disclaimer: I am one of the developers of Catel
Related
I have a detail view corresponding to a user entity. Each user entity has one or more comment entities, which is represented on the detail view as a grid.
So following EF convention, the user model has a UserComments member to represent the relation:
public partial class User
{
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<UserComments> UserComments { get; set; }
//....
}
When it came time to create the user comments grid in the user detail view, I realized that the grid does not properly bind to an ICollection (couldn't add new rows to the grid). After some digging, I found that I needed to use an ObservervableColletion. Ok, so I converted my ICollection into an ObserverableCollection....
public class UserDetailViewModel
{
public virtual User UserData { get; set; }
private ObservableCollection<UserComments> _UserComments;
public ObservableCollection<UserComment> UserComments {
get { return _UserComments; }
}
public void Load(int UserID)
{
this.UserData = UserRepo.Find(UserID);
this._UserComments = new ObservableCollection<UserComment>(UserData.UserComments);
}
}
Cool. I can add rows to the grid now. But...
At this point, I've realized I've lost EF change tracking by converting User.UserComments to an ObservableCollection and have no easy way of getting the modifed/new comments back into EF.
So have I approached this all wrong? Is there a better way of updating the related data?
In order for EF to track collection changes, you need to be adding and removing from the collection in the model itself.
this._UserComments = new ObservableCollection<UserComment>(UserData.UserComments);
In the line above, you're creating a collection by copying elements, so when items are added to or removed from UserDetailViewModel.UserComments, those items aren't actually being added to or removed from User.UserComments.
Some options to fix this include:
Changing User.UserComments itself to an ObservableCollection and exposing that in the view model. For example:
public class UserDetailViewModel
{
public virtual User UserData { get; set; }
public ObservableCollection<UserComment> UserComments
{
get { return UserData.UserComments; }
}
// other stuff...
}
Handling add/remove events for UserDetailViewModel.UserComments and modifying the User.UserComments collection there.
This might be helpful as well:
https://msdn.microsoft.com/en-us/data/jj574514.aspx
I have something like this:
public class ModelEntity : Entity
{
public override int Id { get; set; }
public string FileName { get; set; }
}
public class DataTransferObject
{
public int Id { get; set; }
public string FileName { get; set; }
}
And I would like to do something like this:
var model = _fixture.Create<ModelEntity>();
var dto = _fixture.Create<DataTransferObject>().FillWith(model);
Right now I am doing the following but I am not sure if is the right way to do it
var model = _fixture.Create<ModelEntity>();
var dto = model.AsSource().OfLikeness<DataTransferObject>().CreateProxy();
AutoFixture doesn't have a feature like that, but I think there's something better to be learned from this:
AutoFixture was originally built as a tool for Test-Driven Development (TDD), and TDD is all about feedback. In the spirit of GOOS, you should listen to your tests. If the tests are hard to write, you should consider your API design. AutoFixture tends to amplify that sort of feedback, and it may also be the case here.
It sounds like you need to be able to populate a DataTransferObject with values from a ModelEntity instance. Could this suggest that some sort of mapping would be a valuable addition to your API?
Depending on how these types are already coupled, you could consider adding a projection method to your ModelEntity class:
public class ModelEntity : Entity
{
public override int Id { get; set; }
public string FileName { get; set; }
public DataTransferObject ToDataTransferObject()
{
return new DataTransferObject
{
Id = this.Id,
FileName = this.FileName
};
}
}
However, the disadvantage of this approach is that it couples those two types to each other.
If you find that undesirable, you could instead introduce a dedicated Mapper Service, which can map a ModelEntity instance to a DataTransferObject object - and perhaps vice versa.
If, for some unfathomable reason, you don't want to introduce such a Mapper into your System Under Test, you can still add it as a reusable Service in your test project.
If you don't wish to write such a Mapper yourself, you could consider using something like AutoMapper for that purpose.
Inside an AngularJS directive, I assign a new value to a scope variable:
$scope.myPerson = { TiersId: 105191, Name: "John Smith" };
Originaly the $scope.myPerson was created from a BreezeJS entity.
Assigning the new value triggers a $scope.apply() by AngularJS, which is then intercepted by BreezeJS. That's when it gets complicated.
[EDIT]
Ok, I've figured out that I need to use the EntityManager that I've registered with my dataContext:
$scope.myPerson = myDataContext.createPerson({ TiersId: 105191, Name: "John Smith" });
function createPerson(person) {
return manager.createEntity("AccountOwner", person);
}
Now, it fails in the following code:
proto.createEntity = function (typeName, initialValues, entityState) {
entityState = entityState || EntityState.Added;
var entity = this.metadataStore
._getEntityType(typeName)
.createEntity(initialValues);
if (entityState !== EntityState.Detached) {
this.attachEntity(entity, entityState);
}
return entity;
};
The entity type is known, but the createEntity(initialValues) function is undefined. How come ?
[EDIT]
To make things clearer, here's the relevant EF mapping as well as the model classes:
public class MandateMappings : EntityTypeConfiguration<Mandate>
{
public MandateMappings()
{
Property(m => m.IBAN).HasMaxLength(34).IsFixedLength().IsUnicode(false);
Property(m => m.AccountOwner.Name).HasMaxLength(70);
Property(m => m.AccountOwner.City).HasMaxLength(500);
Property(m => m.CreatedBy).HasMaxLength(30);
Property(m => m.UpdatedBy).HasMaxLength(30);
}
}
public class Mandate : Audit
{
public string IBAN { get; set; }
public AccountOwner AccountOwner { get; set; }
}
public class AccountOwner
{
public string Name { get; set; }
public string City { get; set; }
}
public abstract class Audit
{
public DateTime CreatedDate { get; set; }
public string CreatedBy { get; set; }
}
Let me clarify what I meant when I said on User Voice that Breeze supports a form of inheritance but not "database inheritance".
I meant that, today, the classes on your server-side can be part of an inheritance chain if and only if that chain is invisible to the client.
Here are some conditions consistent with that caveat:
Only the "terminal" class in the chain (the most derived class) maps to a database table.
Properties on super classes are non-public (e.g., internal) or explicitly not mapped (e.g., adorned with [System.ComponentModel.DataAnnotations.Schema.NotMapped].
Methods may appear on any class at any level as these are never transmitted to the client.
Here is an example of a TodoItem class that inherits from a baseClass:
public class baseClass
{
public void DoNothing() {}
internal string Foo { get; set; }
}
public class TodoItem :baseClass
{
public int Id { get; set; }
[Required, StringLength(maximumLength: 30)]
public string Description { get; set; }
public System.DateTime CreatedAt { get; set; }
public bool IsDone { get; set; }
public bool IsArchived { get; set; }
}
This works fine on the server. Set a breakpoint in the controller: you'll have no trouble executing DoNothing() and getting/setting the Foo property.
This works because there is no client-side consequence of this structure. The metadata are no different after deriving from baseClass than they were before. The Foo property and DoNothing methods are invisible to the client … exactly as this service author intended.
This kind of arrangement is pretty common in the real world where the many classes of a business model share functionality through a base class.
This is NOT the end of the story and it is NOT what we think people are asking for when they ask for "inheritance".
We think people want what I have been calling "database inheritance" by which I mean that two or more classes in the inheritance chain are mapped to different tables.
Breeze does not handle that today ... in part because Breeze cannot yet comprehend metadata that describe an inheritance hierarchy.
Workaround
What if you had a class hierarchy in which data properties were defined on different class levels? You can workaround the current obstacles by providing a metadata description that flattens the hierarchy from the perspective of the client.
For example, suppose you have a Person type with FirstName and LastName. And Person derives from entityBase which defines createdBy.
If you define the Person *EntityType* to have [FirstName, LastName, and createdBy] properties - essentially flattening the hierarchy - all will be well.
Flatten the hierarchy automagically
Of course that's a PITA. One approach to inheritance we could take is to do this flattening for you when you ask Breeze to generate the metadata on the server.
I'm curious: would this suffice? Or do you really NEED to know on the JavaScript client that the createdBy property belongs to a base class. If you really need to know, please tell me why.
Edit: As of v 1.3.1 Breeze now DOES support inheritance.
Without more context I can't be sure, but I'm guessing that the issue is that Breeze does not YET have metadata about your entityType. Normally this is accomplished via your first query, but if you are creating entities before the first query then the alternative is to call the EntityManager.fetchMetadata() method instead BEFORE performing any createEntity calls. The fetchMetadata method is asynchonous, i.e. returns a promise, so you will need to perform your createEntity call inside of the 'then' portion of the promise. There are a couple of other recent 'Breeze' posts similar to this that have more details and examples.
Look at this complex type, which is basically a DTO that wraps some entities. I don't need to track these entities or use the for updating or any of that stuff, I just want to send them down to the client. The stuff at the top are non-entities just to let me know that I'm not crazy.
public class ResultDetail
{
// non entities (some are even complex) - this works GREAT!
public string WTF { get; set; }
public IEnumerable<int> WTFs { get; set; }
public SomethingElse StoneAge { get; set; }
public IEnumerable<SomethingElse> StoneAgers { get; set; }
// these are entities - none of this works
public EntityA EntityA { get; set; }
public IEnumerable<EntityB> EntityB { get; set; }
}
public class SomethingElse
{
public int ShoeString { get; set; }
}
Now look at this:
http://i.snag.gy/tI9O9.jpg
Not a single entity property shows up on the client side generated types. Are there attributes or something that I can or do I really need to create DTO objects for every one of these entity types? There are more than 2 as in my sample and they have many properties.
By the way these entity types have been generated on the client because of the normal query operations in the domain service that work with them.
This is not possible as current Ria services framework is mainly designed for tracking entities, and for Ria services it is not possible to detect which properties to serialized and which to note, since every entity has navigation properties, serializing properties may cause infinite loops or long loops as there is no control over how to navigate object graph.
Instead you are expected to program your client in such way so that you will load relations on demand correctly.
Ok, I asked this question before, but deleted it as the way I went about describing my problem was wrong.
Firstly, let me state that Im creating a .NET3.5 Winforms app using C# and Plinqo (Professional Linq to Objects) as my ORM. Here's my situation: I have a DataGridview that is populated from a SortableBindingList<T> - in my case, formed from a List<Task> which is simply represented as follows:
public class Task {
public long TaskID { get; set; }
public string TaskDescription { get; set; }
public enumPriority TaskPriority { get; set; }
public DateTime DueDate { get; set; }
public double PercentageComplete { get; set; }
}
Now, I want to provide a Dialog to my user to allow him/her to Filter this list. I envision passing in a list of property names and associated DataType into the Dialog that I can use to populate a ComboBox. So the user will choose which property they want to query from the comboBox and based on the selection the appropriate comparers and UI control will be made available for the user to enter in thier criteria. Lastly, it will contain an AND/OR togglebutton at the end which the user can use to add additional criterion. Each criterion will be an object of type FilterItem as shown below:
public class FilterItem {
public string MappedPropertyName { get; set; }
public enumComparer Comparer { get; set; }
public object FilterValue { get; set; }
public enumOpertor Operator { get; set; }
}
After the user constructs his/her query, I intend to pass this as a List<FilterItem> back to my calling form, which can then iterate thru the list and allow me to filter the original List<Task>.
This is all fine, and something that I can put together with ease. But I want to make sure that the ACTUAL filter mechanism I go with is as strongly-typed as possible, and not using bulit up strings like in the Dynamic Query Library. (I used to do something similar previously with ADO.NET, DataViews and dynamically constructing a RowFilter string)
I've read up on Joseph Albahari's PredicatBuilder and an article on tomasp.net, but I seem heavily confused with it and expression trees in general.
I sincerely seek your assistance in helping me better understand these concepts, and how to go about using it up so that my intended architecture can work with it.
Much appreciation!
Additionally, I know I can do something like:
private SortableBindingList<Task> GetSortedTaskList()
{
List<Task> list = new List<Task>();
var query = DataUtil.GetUserTasks(xSys.Current.UserID);
if (/*description condition met*/)
{
query = query.Where(x => x.TaskDescription.Contains(FilterDesc));
}
if (/*due date condition met*/)
{
query = query.Where(x => x.DueDate >= FilterDate);
}
if (/*priority condition met*/)
{
query = query.Where(x => x.TaskPriority == FilterPriority);
}
...
list = query.ToList();
return new SortableBindingList<ArcTask>(list);
}
but this does not seem very scalable and 'dynamic'.