I'm bulding a WPF application on visual studio 2013 with Entity-Framework (Code First).
I have a Order class, that has a virtual property for Customer.
public class Order
{
public int OrderId { get; set; }
public DateTime OrderDate { get; set;}
public virtual Customer Customer { get; set; }
}
public class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; }
public string DocumentNumber { get; set; }
public DateTime BirthDate { get; set; }
}
I'm trying to show the customer's name on report formula. I've tried:
=First(Fields!Customer.Value.Name, "MyDataSet")
=First(Fields!Customer.Name.Value, "MyDataSet")
and
=Fields!Customer.Value.Name
=Fields!Customer.Name.Value
It just shows #Error on that field. Other fields from Order are displayed properly.
It works:
=First(Fields!OrderDate.Value, "MyDataSet")
I loaded the Customer by using Include when I retrieve the entity from context. So a null reference is not the problem.
Order order = context.Orders.Include(o => o.Customer).Where(o => o.OrderID == id).FirstOrDefault();
I searched the following and others, but sounds like is just for visual studio 2010 or just didn't work:
Bind child object property with in rdlc (Report)
http://wraithnath.blogspot.com.br/2011/04/reportviewer-object-datasource-nested.html
Is there some thing I didn't do or I should work another way on that, like some kind of "code-first-view"?
This answer worked for me in VS2013:
http://wraithnath.blogspot.com/2011/04/reportviewer-object-datasource-nested.html
Be sure you classess fullfill with the requirements, remember add the parameterless constructor, (it only worked for me until i added the parameterless constructor)
Checklist:
ALL classes are serializable (every user type in the class must be
serializable, and any user type in a property of a usertype must be
serialzable)
ALL classes have a public parameterless constructor
ALLclasses used in the report must have the public modifier
If any property of the datasource, or any property of a property cannot be
serialized then your will get the #Error. Just make sure everything
is serializable
Make sure there will be no infinite recursion issues eg, class A has a
property of class B, and class B has a property of class A. Use XMLIgnore / ScriptIgnore attributes
This are my classes:
[Serializable]
public class Person
{
public Person()
{
}
public string Name{ get; set; }
public string Address1{ get; set; }
public string Id{ get; set; }
public string Phone { get; set; }
}
Parent:
[Serializable]
public class Header
{
public Header()
{
}
public string Product { get; set; }
public DateTime EmisionDate{ get; set; }
public string Number { get; set; }
public Person Person { get; set; }
}
And this is my expression
=First(Fields!Person.Value.Name, "dsHeader")
I'm not sure if this is the accepted standard for doing this kind of thing but what I've found to be the most reliable. (VS Rdlc work is bugged to hell and not well documented in the wpf realm)
So you have your dataset for your 'Order' object which contains the customer object you're trying to access properties from. Now, create another dataset of the 'Customer' object.
Then in code, populate your 'Order' object with everything as you normally would and then set the second dataset's binding source we created based on your 'Customer' object to the 'Customer' object that is inside your 'Order' object
Order order = new Order();
order.OrderId = 1;
order.OrderDate = DateTime.Now;
order.Customer = new Customer("John", "Shmoe");
OrderBindingDataSet.DataSource = order;
CustomerBindingDataSet.DataSource = order.Customer;
Hope this helps, I know from personal experience how irritating it is to have to use this piece of work along with it having little to no documentation for these kind of things. :)
Related
The issue:
Entity object has it properties related to databases on its own, but the needs in the programming area is differ, sometimes we want to add it some more:
Properties – that is for temporary logic.
Methods – for clean code and for programming necessaries.
Finally yet importantly – Attribute for authorization, display, filters etc.
However, obviously we do not want our program to be maintainability without needs to rewrite code just after we update the model.
For properties and methods, the Entity Framework platform generated all the object from model as partial classes and the .NET environment allow us to extend them as we wish:
Remember to check that our partial sit in same namespaces (Notice that when we create them in model directory or in them own directory Visual Studio create addition namespace).
public partial class ErrorLog
{
public long pk { get; set; }
public int lineNumber { get; set; }
public Nullable<int> error { get; set; }
}
Our partial:
public partial class ErrorLog
{
public string getErrorDescription()
{
return d[(int)error];
}
private static Dictionary<int, string> d = new Dictionary<int, string>()
{
{1,"desc1" },
{2,"desc2" },
{3,"desc3" },
{4,"desc4" }
};
}
For attributes:
We can add new interface
public interface IErrorLogsMetaData
{
[Display(Name = "Id")]
long pk { get; set; }
[Display(Name = "The line Number")]
int lineNumber { get; set; }
[Display(Name = "The Error")]
Nullable<int> error { get; set; }
}
Implement them on our Entity (even extended) object.
For that we need to reflect and book it in global.asax by using:
TypeDescriptor.AddProviderTransparent(
new AssociatedMetadataTypeTypeDescriptionProvider(typeof(ErrorLog), typeof(IErrorLogsMetaData)), typeof(ErrorLog));
TypeDescriptor – familiar for us from reflection, its get information about type.
AddProviderTransparent – is the method called from my partially trusted code and get metadata from associated class.
The first parameter is the provider and it TypeDescriptionProvider from the type we want to decorate and the attributed interface, the second parameter is the target type for decription.
Another Option
Make your partial view to implement the IErrorLogsMetaData and then you don't need to associate at Global.asax
As you can see, the database first entity model classes are partial, so you can create your own partial class, for example if you have:
public partial class SomeClass
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
You can do something like this:
Add some class to your project, name it SomeClassPartial:
//SomeClassPartial.cs
namespace YourNamespace
{
[MetadataType(typeof(SomeClassMetadata))]
public partial class SomeClass
{
//add your new properties/some_logic here
public string NewPropX { get; set; }
public string NewPropY { get; set; }
}
public partial class SomeClassMetadata
{
//metadata for your existing model properties
[Display(Name = "Property 1")]
public string Prop1 { get; set; }
[Display(Name = "Property 2")]
public string Prop2 { get; set; }
}
}
In your SomeClassMetadata class you can add data annotation attributes to your existing properties with MetadataType attribute, which will specify the metadata class to associate with a data model class, and with that you can tell you partial SomeClass class to get that attributes from SomeClassMetadata class. To add new custom properties, you can use SomeClass partial class.
MSDN Link: MetadataTypeAttribute Class
I am migrating /re-developing a web app from JavaScript to the ASP.NET MVC Framework using C#/ JS (with Handlebars.NET) for my Bachelor thesis.
So far I have created a Web.API and the actual app with a form.
In the app I enter details to create a new Employee, which is then Posted to the API, which receives that Json-Object as a "Business Object" BOEmployee.
Said BOEmployee looks like this (simplified):
public class BOEmployee
{
public int ID_Employee { get; set; }
public int ID_Company { get; set; }
public string lastName { get; set; }
public string firstName { get; set; }
}
I want to map this object to two other objects, representing tables of the underlying database, to then save them to the database. The two target tables are auto generated with Entity Framework.
Here are the table objects:
1. Employee:
public partial class Employee
{
public int ID_Employee { get; set; }
public int ID_Company { get; set; }
}
2. Employee_Details:
public partial class Employee_Detail
{
public int ID_Employee_Detail { get; set; }
public int ID_Employee { get; set; }
public string lastName { get; set; }
public string firstName { get; set; }
}
Now I could map them manually by assigning every attribute but clearly that is a horribly unsustainable idea. So I was looking for a way to automate that mapping process automatically using Json.Net like this:
[HttpPost]
public BOEmployee SaveEmployee([FromBody] string employee)
{
using (var context = new myDBEntities())
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
Employee_Detail dbEmployeeDetails = serializer.Deserialize<Employee_Detail>(BOEmployee);
Employee dbEmployee = serializer.Deserialize<Employee>(BOemployee);
}
}
Now what happens when I run that code is, that the serializer-function complains that the input values cannot be null, which to my understanding is because the target Objects (e.g. Employee) do not have all attributes that are given in the serialized Json-Object.
The Error Message is this:
Value cannot be null.\r\nParameter name: input",
"ExceptionType":"System.ArgumentNullException"
Now my question would be, how can I map my object to the different Database tables? Or am I completely on the wrong path now?
Fundamental changes to the program structure cannot be made any more due to available time (and I am basically a complete beginner in programming).
I recommend AutoMapper than what you are using there.
I'm using MVC5 with EF6 .I'm getting the below conversion Error
Cannot implicitly convert type
System.Collections.Generic.List<TreaceabilitySystem.GLB_M_PROFITCENTER>
to
System.Collections.Generic.List<TreaceabilitySystem.Models.Profitcenter>
private TSEntities db = new TSEntities();
// GET: Profitcenter
public ActionResult Index()
{
List<Profitcenter> profitcenter = new List<Profitcenter>();
profitcenter = db.GLB_M_PROFITCENTER.ToList(); //Error coming up here
return View(profitcenter.ToList());
}
My models are here:
This Model created through EF when i add table in .edmx
public partial class GLB_M_PROFITCENTER
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public GLB_M_PROFITCENTER()
{
this.GLB_M_USERMASTER = new HashSet<GLB_M_USERMASTER>();
}
public string PROFITCENTER_CODE { get; set; }
public string PROFITCENTER_NAME { get; set; }
public string DESCRIPTION { get; set; }
public bool ISACTIVE { get; set; }
public int CREATEDBY { get; set; }
public System.DateTime CREATED_DATE { get; set; }
public Nullable<int> UPDATEDBY { get; set; }
public Nullable<System.DateTime> UPDATED_DATETIME { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<GLB_M_USERMASTER> GLB_M_USERMASTER { get; set; }
}
And I have created the below model for change the display name and validation purposes
[MetadataType(typeof(Profitcenter))]
public partial class GLB_M_PROFITCENTER { }
public class Profitcenter
{
[Required(ErrorMessage = "*")]
[DisplayName("Profitcenter Code")]
public string PROFITCENTER_CODE { get; set; }
[Required(ErrorMessage = "*")]
[DisplayName("Profitcenter Name")]
public string PROFITCENTER_NAME { get; set; }
[DisplayName("Description")]
public string DESCRIPTION { get; set; }
[DisplayName("Is Active")]
public bool ISACTIVE { get; set; }
[DisplayName("Created By")]
public int CREATEDBY { get; set; }
[DisplayName("Created Timestamp")]
public System.DateTime CREATED_DATE { get; set; }
[DisplayName("Upated by")]
public Nullable<int> UPDATEDBY { get; set; }
[DisplayName("Updated Timestamp")]
public DateTime UPDATED_DATETIME
{
get; set;
}
}
both models are exactly same , Am I missing anything ?
How do I fix this?
both models are exactly same
That doesn't mean you can just assign the one to the other. For this code to work:
Foo foo = new Foo();
Bar bar = foo;
Bar must be a base type of Foo. This isn't the case here, both your Bar and Foo just happen to have the same property names.
You need to map from one to the other:
public Profitcenter Map(GLB_M_PROFITCENTER input)
{
return new Profitcenter
{
PROFITCENTER_CODE = input.PROFITCENTER_CODE,
...
};
}
You can do the mapping of the entire list with Select():
List<Profitcenter> profitcenter = new List<Profitcenter>();
profitcenter = db.GLB_M_PROFITCENTER.Select(Map).ToList();
An automated way of doing this could be using AutoMapper, which works especially well if all properties on both sides are named identically.
That only answers your question partially though. You have two types: GLB_M_PROFITCENTER, an Entity Framework-generated class that represents a database table, and Profitcenter, where you have added attributes that can be used for input validation using the MetadataType attribute.
I'm not a fan of the latter, because you're then using Entity Framework models as viewmodels for your UI layer. You shouldn't, and you can just remove the MetadataType attribute from the partial class definition.
So you can either use the MetadataType, but then never really instantiate that type (after all, it is a metadata type):
List<GLB_M_PROFITCENTER> profitcenter = db.GLB_M_PROFITCENTER.ToList();
return View(profitcenter);
And make your view #model IEnumerable<GLB_M_PROFITCENTER>. Then MVC will read the MetadataType attribute for GLB_M_PROFITCENTER, and apply the metadata (DisplayName, ...) as applied to Profitcenter (but you shouldn't).
Or you can simply apply mapping, thereby decoupling your view model from your entity model (and thus your database), with all additional benefits.
Some programming languages, unlike C# and other C-like languages, allow for what is called "duck typing", which would let you assign from different types if they both "quack the same way".
In C#, however, you can only assign an instance of a class to a variable of the same type, or of a base type (a class which your class extends, or an interface which it implements). Even if you had two classes which looked exactly the same, you wouldn't be able to assign from one of them to the other. .NET prior to version 4.0 didn't even support proper generic covariance and contravariance, meaning you couldn't even assign a IEnumerable<Tderived> to IEnumerable<Tbase> even if Tderived is derived from Tbase.
The solution could be to:
use a tool which will map from one class to the other (i.e. copy between equally named properties), like AutoMapper, or
redesign your app to have a separate assembly which contains common entities to be shared between other assemblies type (not a bad idea either), or
extract an interface so that you can assign to this base interface.
It is not uncommon to use mapping to resolve this issue, since you often want to have plain data transfer objects for moving data between tiers, so using an automated tool for this is ok, but if you can keep all entities in a separate assembly which is referenced by both DAL and business layer, but doesn't know anything about them, then it's an even better approach because it avoids any runtime mapping issues.
GLB_M_PROFITCENTER and Profitcenter are not same types, you just share metadata for sharing of attributes from viewmodel to entity model. You should use linq projection for conversion of one type to other
db.GLB_M_PROFITCENTER.select(e => new Profitcenter() {
/* props mapping*/
}).ToList()
you can also use mapping engine for example AutoMapper
If the member names are the same - use auto mapper - it will automatically convert each type.
Mapper.CreateMap<SourceType, DestinationType>()
Then you can call
Mapper.Map<DestinationType>(instanceofSourceType);
I'm trying to dynamically assign a value from DB to a property which inherits from EpiServer PageData class. Here is what I mean:
namespace Episerver9.Models.Pages
{
[ContentType]
public class StartPage : PageData
{
public virtual string Username { get; set; }
public virtual string Password { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
[ReadOnly(false)]
[Editable(true)]
public virtual string testfield { get; set; }
}
}
And in controller I'm trying the following:
namespace Episerver9.Controllers
{
public class StartPageController : PageController<StartPage>
{
// GET: StartPage
public ActionResult Index(StartPage currentPage)
{
currentPage.testfield = "test";
return View(currentPage);
}
}
}
And this is what I'm trying to display in the view:
#Html.PropertyFor(x=>x.testfield)
// Trying to dynamically populate the data from code, later on from DB
The error that I'm getting is:
Additional information: The property testfield is read-only
This happens even tho I clearly specified for the property that IT IS NOT read only... Does anyone knows why?
This is because ContentData objects are always read-only for performance purposes. To change any properties, you have to create a writable clone like:
currentPage.CreateWritableClone()
That will give you an instance of your page that you can change, for example to save changes using an IContentRepository instance.
However, note that these instances are read-only for a reason. :) You're better off creating a separate view model that you pass to your view.
I need to validate two fields only if a third field has a specific value.
In this code snipper i suppose to use a CheckIf properties that not exist.
It is possible to validate a field only if another property hase a specifica value ?
public string CustomerType { get; set; } // P=Private B=Business
[NotNullValidator(MessageTemplate = "You must specify the property 'Name'", CheckIf = "CustomerType=='P'")]
public string PrivateName { get; set; }
[NotNullValidator(MessageTemplate = "You must specify the property 'Name'", CheckIf = "CustomerType=='B'")]
public string BusinessName { get; set; }
Thank you!!!
From a validation perspective I agree with Siva that you can use SelfValidation for this. When looking at your code however, from an OO perspective, I can't help noticing that it might be good to take a good look at your design. It seems that either you are showing us two sub types of Customer, namely PrivateCustomer and BusinessCustomer:
class Customer
{
}
class PrivateCustomer : Customer
{
public string PrivateName { get; set; }
}
class BusinessCustomer : Customer
{
public string BusinessName { get; set; }
}
Or... those two properties are actually the same thing. Your validation messages even calls them 'Name' in both cases. In that case, you'll end up with this design:
class Customer : Customer
{
public string CustomerType { get; set; }
public string Name { get; set; }
}