I've searched a lot and I think this is possible, but I feel like I am just blocked from knowing how to properly format it.
I have a class representing a product that is a relation class from our CRM to Magento.
Inside the constructor, I have to do some stuff like this...
public Product(IBaseProduct netforumProduct, MagentoClient client)
{
Product existingMagentoProduct = client.GetProductBySku(netforumProduct.Code);
if (existingMagentoProduct != null)
{
this.id = existingMagentoProduct.id;
this.name = existingMagentoProduct.name;
... many of them ...
this.visibility = existingMagentoProduct.visibility;
this.extension_attributes.configurable_product_links = existingMagentoProduct.extension_attributes.configurable_product_links;
}
else
{
// its a new product, new up the objects
this.id = -1;
this.product_links = new List<ProductLink>();
this.options = new List<Option>();
this.custom_attributes = new List<CustomAttribute>();
this.media_gallery_entries = new List<MediaGalleryEntry>();
this.extension_attributes = new ExtensionAttributes();
this.status = 0; // Keep all new products disabled so they can be added to the site and released on a specific day (this is a feature, not an issue / problem).
this.attribute_set_id = netforumProduct.AttributeSetId;
this.visibility = 0;
}
}
It seems silly to have to initialize all of the properties like that. I could use a mapper but that seems like a bandaid. I have to see if the product exists in magento first, and populate its ID and values, otherwise whenever I save the product it creates an additional one.
I considered doing the class constructor calling a static method, but I couldn't get the syntax right.
It might just be too late and I need to think about something else for awhile.
If you must do it in the constructor, you can get rid of a lot of code by first setting 'default' values to the 'Product' properties. This will remove the need to do them in the constructor. Next, if you wanted to automatically set the class's properties, you can use reflection.
public class Product
{
public int Id { get; set; } = -1;
public List<ProductLink> Product_Links { get; set; } = new List<ProductLink>();
....
public int Visibility { get; set; } = 0;
public Product(IBaseProduct netforumProduct, MagentoClient client)
{
var existingMagentoProduct = client.GetProductBySku(netforumProduct.Code);
if (existingMagentoProduct != null)
{
foreach (PropertyInfo property in typeof(Product).GetProperties().Where(p => p.CanWrite))
{
property.SetValue(this, property.GetValue(existingMagentoProduct, null), null);
}
}
}
}
Though, I would like to point out that you probably shouldn't be using a REST client inside a class constructor, especially to just populate its data (also, you are performing a synchronous operation). It would be cleaner to have another layer that is responsible for populating this class using the client, and then use something like AutoMapper to map the data to it.
Related
We've got a WPF app with a landing page that lists about a dozen or so buttons, all going to new views/viewmodels of that type. Its becoming unwieldy. We've got one viewmodel that lists all of these which basically look like this:
private void ExecuteViewProgramCommand()
{
OpenViewMessage message = new OpenViewMessage();
CurrentViewModel = message.ViewModel = ViewModelLocator.ProgramVM;
Messenger.Default.Send<OpenViewMessage>(message);
}
I've never liked how this was done, as it violates the DRY principle. The only thing that changes in the the above code in the second line, where in this code what changes is ViewModelLocator.ProgramVM. I've been tasked with redoing the landing page, making it more organized and we're going to be adding more launching buttons. I think it would be better to use dependency injection. Also I'm trying to address the need to redesign the display, so that its in a list, rather than buttons scattered about, and in alphabetical order.
First I came up with this class:
public class Tile
{
public string ModuleName { get; set; }
public NamedViewModelBase ModuleViewModel { get; set; }
}
(NamedViewModelBase is the name of the viewmodel that's common to all of the viewmodels.) Then I declared a unit test to test this and declared this within the unit test:
List<Tile> tiles = new List<Tile>()
{
new Tile()
{
ModuleName = "Program",
ModuleViewModel = ViewModelLocator.ProgramVM
},
new Tile()
{
ModuleName = "Organization",
ModuleViewModel = ViewModelLocator.OrganizationVM
}
}
But this quickly became apparent that this was wrong. The assigning in the setter of ViewModelLocator.ProgramVM would instantiate the viewmodel for Program. I don't want that, I'd rather have the calling of instantiating it, such as we have in the ViewModelLocator:
static public ProgramViewModel ProgramVM
{
get
{
if (ServiceLocator.IsLocationProviderSet)
{
SimpleIoc ioc = ServiceLocator.Current as SimpleIoc;
return ioc.GetInstanceWithoutCaching<ProgramViewModel>(Guid.NewGuid().ToString());
}
else
{
return null;
}
}
}
So, I'm thinking that I've got to change the Tile class to declare the ModuleViewModel property to something like this: public NamedViewModelBase ModuleViewModel { get; }. But I don't know how I'd instantiate it when defining a List. What is the correct way to resolve this?
This is going to be psuedo codish advice which is kind of on the same track where you already are:
Assuming BaseViewModel is the base class for all your individual VM's
Create a Dictionary<string, BaseViewModel>
Fill this dictionary up during Application Start time (would look like your tiles List)
public void PreCreateVMs()
{
dictionary[Key] = new ConcreteViewModelType();
// Keep adding New Vms here
}
In the xaml, bind all your buttons to same Command which takes a string argument (or improvise this with Enum). Pass the correct String Key for each button.
Like: Accounts Button click should launch AccountVM which is stored with "AccountVM" key in the dictionary.
In the Command Handler - use the string, lookup the Dictionary find the correct ViewModel and Assign this object to CurrentViewModel
From maintenance point of view - all you need to add a new ViewModel is to update xaml with a new button, assign correct command parameter string. Use this string key and add the correct VM in the PreCreateVMs method.
I've redesigned the Tile class. What I believe I need is for the second parameter to be a Command. I'm asking if this might do better. Here's the new definition of Tile and an example of how I tried to implement it:
public class Tile
{
public string ModuleName { get; set; }
//public NamedViewModelBase ModuleViewModel { get; set; }
public Action ThisCommand { get; set; }
}
And here's how I tried to implement it as a List:
List<Tile> tiles = new List<Tile>()
{
new Tile()
{
ModuleName = "Program",
ThisCommand = () =>
{
if (ServiceLocator.IsLocationProviderSet)
{
SimpleIoc ioc = ServiceLocator.Current as SimpleIoc;
ioc.GetInstanceWithoutCaching<ProgramViewModel>(Guid.NewGuid().ToString());
}
}
},
new Tile()
{
ModuleName = "Organization",
ThisCommand = () =>
{
if (ServiceLocator.IsLocationProviderSet)
{
SimpleIoc ioc = ServiceLocator.Current as SimpleIoc;
ioc.GetInstanceWithoutCaching<OrganizationViewModel>(Guid.NewGuid().ToString());
}
}
}
};
Am I on the right track? Should I define tiles as a Dictionary instead?
I'm using EF(db first) and trying to add new row in table using the next code:
var user = new User();
//Some logic to fill the properties
context.Users.AddObject(user);
context.SaveChanges();
Before saving changes on EF i want to verify that all required (not null and with no default value) properties are filled. How can i get all such fields?
I've tried few ways, but can't achieve needed result. The last try was like that:
var resList = new List<PropertyInfo>();
var properties = type.GetProperties(BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.Instance).Where(p => !p.PropertyType.IsGenericType);
foreach (var propertyInfo in properties)
{
var edmScalarProperty =
propertyInfo.CustomAttributes.FirstOrDefault(
x => x.AttributeType == typeof (EdmScalarPropertyAttribute));
var isNullable = true;
if (edmScalarProperty != null)
{
var arg = edmScalarProperty.NamedArguments.FirstOrDefault(x => x.MemberName == "IsNullable");
if (arg != null)
{
isNullable = (bool) arg.TypedValue.Value;
}
}
if (!isNullable)
{
resList.Add(propertyInfo);
}
}
return resList;
Create a constructor with the required fields as parameters.
I always separate my domain objects from my EF objects (DTO objects). The domain object has only one constructor with the required fields. When I want to save these objects I convert them to DTO objects.
Have you looked at all into DataAnnotations for your model classes? Utilizing these (and using a separate object from the one EF creates for you) you can get pretty significant validation built into your models from the model level. Additionally, as L01NL pointed out, you can have your constructor take in parameters that require data.
Lots of information on Model and Validation can be found, one such example is:
http://msdn.microsoft.com/en-us/library/dd410405(v=vs.100).aspx
(look through this main section and its subsections)
using System.ComponentModel.DataAnnotations
public class Foo
{
public Guid Id { get; private set; }
[StringLength(50),Required]
public string FooName { get; private set; }
[Required]
public int Age { get; private set; }
// etc props
public Foo(string fooName, int age)
{
if (string.IsNullOrEmpty(fooName))
throw new ArgumentException("FooName cannot be null or empty"); // note there is also a "minimum length" data annotation to avoid doing something like this, was just using this as an example.
this.Id = Guid.NewGuid();
this.FooName = fooName;
this.Age = age;
}
}
public class YourController
{
[HttpPost]
public ActionResult Add(Foo foo)
{
if (!ModelState.IsValid)
// return - validation warnings, etc
// Add information to persistence
// return successful add?
}
}
I'm using EF6, and I'm wanting to move the initialisation of my collections to the Entity itself, so the code can be written once, the tutorials don't do this, just wondering if it's ok? I don't know enough about the Entity Frameworks under the hood stuff yet to know if this is ok.
For example:
[NotMapped]
private List<MySuggestion> _mySelections;
public virtual ICollection<MySuggestion> mySuggestions {
get
{
if (_mySelections == null)
{
_mySelections = new List<MySuggestion>();
}
return _mySelections;
}
set;
}
With the alternative being that the list be init'd as required in the Controller/Repository, with something like:
if (thing.mySuggestions == null){
thing.mySuggestions = new List<Suggestion> ();
}
That should work fine. You'll need to specify a body for the setter though...
set
{
_mySelections = value;
}
I am using Domain Service to fetch data from database from Silverlight Client.
In DomainService1.cs, I have added the following:
[EnableClientAccess()]
public class Product
{
public int productID;
public string productName;
public List<Part> Parts = new List<Part>(); //Part is already present in Model designer
}
In DomainService1 class I added a new method to retrive a collection of the custom class object:
[EnableClientAccess()]
public class DomainService1 : LinqToEntitiesDomainService<HELPERDBNEWEntities1>
{
...
public List<Product> GetProductsList(...)
{
List<Product> resultProducts = new List<Product>();
...
return resultProducts;
}
}
From the silverlight client I am trying to access that method:
DomainService1 ds1 = new DomainService1();
var allproductList = ds1.GetProductsList(...);
ds1.Load<SLProduct>(allproductList).Completed += new EventHandler(Load_Completed); //Not correct usage
However it is not the correct way to call the new method. The reason I added a new class Product in DomainServices.cs is to have an efficient grouping. I cannot achieve the same using the model classes auto-generated by the entity framework.
How call I call the new method from the client?
I believe there is a similar question with an answer here:
Can a DomainService return a single custom type?
Also, here is some discussion about the overall problem of adding custom methods in a Domain Service:
http://forums.silverlight.net/t/159292.aspx/1
While I don't know what you mean by "it is not the correct way to call the new method", or if you're getting any errors, I thought maybe posting some working code might help.
My POCO
public class GraphPointWithMeta
{
[Key]
public Guid PK { get; set; }
public string SeriesName { get; set; }
public string EntityName { get; set; }
public double Amount { get; set; }
public GraphPointWithMeta(string seriesName, string entityName, double amount)
{
PK = Guid.NewGuid();
SeriesName = seriesName;
EntityName = entityName;
Amount = amount;
}
// Default ctor required.
public GraphPointWithMeta()
{
PK = Guid.NewGuid();
}
}
A method in the domain service (EnableClientAccess decorates the class)
public IEnumerable<GraphPointWithMeta> CallingActivityByCommercial()
{
List<GraphPointWithMeta> gps = new List<GraphPointWithMeta>();
// ...
return gps;
}
Called from the Silverlight client like
ctx1.Load(ctx1.CallingActivityByCommercialQuery(), CallingActivityCompleted, null);
client call back method
private void CallingActivityCompleted(LoadOperation<GraphPointWithMeta> lo)
{
// lo.Entities is an IEnumerable<GraphPointWithMeta>
}
I am not sure if your Product class is an actual entity or not. From the way it is defined, it does not appear to be an entity. My answer is assuming it is not an entity. You will need to apply the DataMemberAttribute for your Product properties, and you wouldn't load the product list - load is for Entity Queries (IQueryable on the service side). You would just invoke it like this (client side):
void GetProductList( Action<InvokeOperation<List<Product>>> callback)
{
DomainService ds1 = new DomainService();
ds1.GetProductsList(callback, null);//invoke operation call
}
And the domain service's (server side) method needs the InvokeAttribute and would look like this:
[EnableClientAccess]
public class MyDomainService
{
[Invoke]
public List<Product> GetProductList()
{
var list = new List<Product>();
...
return list;
}
}
And here is how your Product class might be defined (if it is not an entity):
public class Product
{
[DataMember]
public int productID;
[DataMember]
public string productName;
[DataMember]
public List<Part> Parts = new List<Part>(); // you might have some trouble here.
//not sure if any other attributes are needed for Parts,
//since you said this is an entity; also not sure if you
//can even have a list of entities or it needs to be an
//entity collection or what it needs to be. You might
//have to make two separate calls - one to get the products
//and then one to get the parts.
}
Like I said, i am not sure what Product inherits from... Hope this helps.
I have a constructor something like the following:
using Microsoft.Data.Extensions;
public class Complaint
{
public int Id {get; set;}
public int Transcript {get; set;}
//... etc. ... Lots more properties
public Complaint(int id)
{
var command = dataContext.CreateStoreCommand(
"dbo.stp_Complaint_Get",
CommandType.StoredProcedure,
new SqlParameter("Id", id));
var complaint = command.Materialize(x =>
new Complaint
{
Id = x.Field<int>("Id"),
Transcript = x.Field<string>("Transcript");
//... etc. ... Lots more fields from db
}
this.Id = complaint.Id;
this.Transcript = complaint.Transcript;
//... etc. ... Lots more properties to set
}
}
Is there a syntax in C# that would allow me to carry out the last part in one step instead of two? i.e. conceptually something like this:
this = command.Materialize(x =>
new Complaint
{
Id = x.Field<int>("Id"),
Transcript = x.Field<string>("Transcript");
}
Well, you could use a static method instead of a constructor:
public static Complaint FromId(int id)
{
var command = dataContext.CreateStoreCommand(
"dbo.stp_Complaint_Get",
CommandType.StoredProcedure,
new SqlParameter("Id", id));
return command.Materialize(x =>
new Complaint
{
Id = x.Field<int>("Id"),
Transcript = x.Field<string>("Transcript");
//... etc. ... Lots more fields from db
});
}
Not inherently. You could store the complaint object inside the class, and have all the properties point off that rather than setting them all from the constructor.
eg
public class Complaint
{
private readonly {type of complaint} m_Complaint;
public int Id
{
get { return m_Complaint.Id; }
}
// ...etc
}
You could get more complicated if you don't have a setter on m_Complaint - keeping nullable backing fields, and check that before you access the m_Complaint properties
I believe you may try something like this:
var currentInstance = this;
var complaint = command.Materialize(x =>
new Complaint
{
Id = currentInstance.Id = x.Field("Id"),
Transcript = currentInstance.Transcript = x.Field("Transcript");
//... etc. ... Lots more fields from db
});
I don't think you can capture this in the closure, so using that currentInstance trick should help, however it may as well turn out to be redundant.
Besides, code such as that one is sort of obfuscated compared to your current solution. I believe that your code is pretty fine as it is.
I gather that you're trying to avoid setting all of those properties twice, because any change to the structure requires you to update the properties in two places, is that correct?. You could try to use some reflection to copy the properties from one instance to another.
var complaint = command.Materialize(x =>
new Complaint
{
Id = x.Field<int>("Id"),
Transcript = x.Field<string>("Transcript");
//... etc. ... Lots more fields from db
}
foreach (var prop in typeof(Complaint).GetProperties())
...
Have the complaint object as a member variable and the get/set properties accesses the underlying complaint's properties?