Entity property look like this:
[Display(Name = "Email")]
public string Email { get; set; }
its for English,
when user select another language this attribute will change at runtime
[Display(Name = "DisplayAnotherSomething")]
public string Email { get; set; }
How do I limit the columns that are returned by web api & entity framework?
I would appreciate as much info as possible as I am still a newbie ;)
My Controller:
//GET: api/Creditors
public IQueryable<Creditor> GetCreditors()
{
return db.Creditors;
}
My Class:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace PurchaseOrders.Models
{
public class Creditor
{
[Key]
public int CreditorID { get; set; }
[MaxLength(10, ErrorMessage = "Maximum of 10 characters")]
public string CRKEY { get; set; }
[Display(Name = "Business Name")]
[MaxLength(40, ErrorMessage = "Maximum of 40 characters")]
public string BusinessName { get; set; }
[MaxLength(40, ErrorMessage = "Maximum of 40 characters")]
public string Address { get; set; }
[MaxLength(40, ErrorMessage = "Maximum of 40 characters")]
public string City { get; set; }
[MaxLength(4, ErrorMessage = "Maximum of 4 characters")]
public string State { get; set; }
[MaxLength(4, ErrorMessage = "Maximum of 4 characters")]
public string Postcode { get; set; }
[MaxLength(15, ErrorMessage = "Maximum of 15 characters")]
public string Phone { get; set; }
[MaxLength(15, ErrorMessage = "Maximum of 15 characters")]
public string Fax { get; set; }
[MaxLength(60, ErrorMessage = "Maximum of 60 characters")]
public string Email { get; set; }
[MaxLength(60, ErrorMessage = "Maximum of 60 characters")]
public string Website { get; set; }
[MaxLength(30, ErrorMessage = "Maximum of 30 characters")]
public string ContactName { get; set; }
[MaxLength(15, ErrorMessage = "Maximum of 15 characters")]
public string ABN { get; set; }
[Display(Name = "Registered for GST")]
public bool RegisteredForGST { get; set; }
}
}
This currently returns:
[{"CreditorID":1,"CRKEY":"test1","BusinessName":"test1","Address":"7 Smith Street","City":"Melbourne","State":"VIC","Postcode":"3000","Phone":null,"Fax":null,"Email":null,"Website":null,"ContactName":null,"ABN":"null","RegisteredForGST":true},{"CreditorID":2,"CRKEY":"test2","BusinessName":"test2","Address":"10 Smith Street","City":"SYDNEY","State":"NSW","Postcode":"2000","Phone":null,"Fax":null,"Email":null,"Website":null,"ContactName":null,"ABN":"null","RegisteredForGST":true}]
This is the result I want (only the "CreditorID" & "BusinessName"):
[{"CreditorID":1,"BusinessName":"test1"},{"CreditorID":2,"BusinessName":"test2"}]
In your question you're showing the json output of the query, so I assume you're making the GET request from Javascript. As you're using the IQueryable as the type of the return value from your API method, you should be able to take advantage of the OData support that WebApi provides so that you can issue an OData query to select just the columns you want. This this article for more detail on the OData support.
So firstly, the javascript side, assuming jQuery for ease of answering:
$.get('api/Creditors?$select=CreditorId,BusinessName', onSuccess)
The column names you want are specified in a comma separated list in the $select argument. (The onSuccess is a callback function you would define which would be passed the data that comes back from the API. See the jQuery documentation for more details.)
On the server side, you might need to derive your controller from ODataController instead of ApiController and you will need to add either the [Queryable] or the [EnableQuery] attribute to your GetCreditors() method depending on the version of WebApi you are using.
There is another bit of configuration you have to add if you find that you do need to inherit from ODataController to make this work, and that is to configure the OData endpoint. To do this you will need code similar to the following:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Creditor>("Creditors");
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: null, // or "api" ?
model: builder.GetEdmModel());
}
}
Somewhere in your web startup code (e.g. Application_Start) you will need to call this as follows:
GlobalConfiguration.Configure(WebApiConfig.Register);
Depending on how you've set your project up, some of this latter configuration might not be necessary as it will already be done, but I thought I'd mention it for good measure. Have a look at this page for more details.
This can be done using projection, here is sample using anonymous type:
db.Creditors
.Select(x => new {
x.CreditorID,
x.BusinessName,
})
.ToArray()
This will result in query to database which will get only two fields you need wrapped in anonymous class. You can return it directly from your WebAPI controller with JSON result.
If you need to pass result (which is of type SomeAnonymousClassICanNotReference[]) between layers, you can either use dymanic keyword (not a good option actually), or use your custom class like Select(x => new MyClass { Id = x.CreditorID ...
There are several different ways to handle this requirement without OData. I tend to use a projection query (as Lanorkin mentioned in his answer). Here are some examples.
1. Return a dynamic type from your WebAPI controller:
This is the quickest and easiest method. Some would argue that dynamic return types are sloppy, but they get the job done.
[HttpGet]
public dynamic GetCreditors() {
return db.Creditors
.Select(x => new {
x.CreditorID,
x.BusinessName,
}).ToArray()
}
2. Use an explicit return type in your controller:
This works with WebAPI as well as WCF which does not allow dynamic return types. This is a "better" approach if your standard practice is to use static return types.
Create a class for your return type:
public class CreditorResult {
public int CreditorID { get; set; }
public string BusinessName { get; set; }
}
Then your API method would look like this:
[HttpGet]
public CreditorResult[] GetCreditors() {
return db.Creditors
.Select(x => new CreditorResult() {
x.CreditorID,
x.BusinessName,
}).ToArray()
}
3. Use model attributes to control the output fields:
The current version of WebAPI uses JSON.NET as its serializer, and older versions can be set up to use it too. You can specify data attributes on your model to tell JSON.NET which properties to include or to ignore.
If you're using the code-first approach to Entity Framework then you can add the attributes directly to your class. If you're using the database-first approach (code generation) then it's safest to put your attributes in a Metadata class. http://www.ozkary.com/2015/01/add-data-annotations-to-entity.html
If you only want to include a few fields, you should add [DataContract] to the class and [DataMember] to the properties. Only the properties with [DataMember] will be included in the output. For example, the following would only return CreditorID and BusinessName:
[DataContract]
public class Creditor
{
[DataMember]
[Key]
public int CreditorID { get; set; }
[DataMember]
[Display(Name = "Business Name")]
[MaxLength(40, ErrorMessage = "Maximum of 40 characters")]
public string BusinessName { get; set; }
...
If you want to include most of your fields and ignore a few, the easier option is to add [JsonIgnore] to the properties that you wish to hide.
public class Creditor
{
[Key]
public int CreditorID { get; set; }
[JsonIgnore]
[MaxLength(10, ErrorMessage = "Maximum of 10 characters")]
public string CRKEY { get; set; }
[Display(Name = "Business Name")]
[MaxLength(40, ErrorMessage = "Maximum of 40 characters")]
public string BusinessName { get; set; }
...
There are a lot of other ways to fine-tune the output. Check out http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size for more details.
I create Models for manually showing error. For Example, I have Organization Model. In this i have fields like,
Name
EmailAddress
Mobilenumber
IndustryId.
In the above if any item is not fill in user page, It shows "Name is required" like that.
My code in Model
public class Organization_Validation
{
[Required(ErrorMessage = "Name is required")]
[StringLength(200, ErrorMessage = "Name cannot exceed 50 characters")]
public string Name { get; set; }
[Required(ErrorMessage = "Industry is required")]
[Range(1, int.MaxValue, ErrorMessage = "Industry is required")]
public int IndustryId { get; set; }
[Required(ErrorMessage = "MobileNumber is Required")]
public string MobileNumber { get; set; }
[Required(ErrorMessage = "Email Address is required")]
public string Email { get; set; }
}
Here I want to check Mobilenumber and Email address. Anyone of these two can enter. If user enter Mobilenumber without email means it should not showing error. it will update. How to do this?
You may take a look at FluentValidation.NET which allows you to replace the declarative Data Annotations (which are very limited in such scenarios) with imperative validation rules. It has a great integration with ASP.NET MVC and in addition to that it allows you to easily unit test your validation rules.
I created an mvc 4 web project using database first and entity framework but was surprised to see that default models were not generated automatically, is there a way to create them from my .edmx file or are there any other possibilities to save hand coding them?
Any help would be much appreciated
UPDATE:
Sorry, should have mentioned I am looking for a solution to generate simple models with basic methods such as :
public class EditUserModel
{
public int ID { get; set; }
[Required(ErrorMessage = "Forename is required")]
public string Forename { get; set; }
[Required(ErrorMessage = "Surname is required")]
public string Surname { get; set; }
[Required(ErrorMessage = "Username is required")]
public string Username { get; set; }
}
I ended up making a SQL query to generate a simple mvc model from my tables.
With automatic database recreation, it is uncertain whether referred entities will get loaded or not.
The context is EF CTP 5 and ASP.NET MVC 2. In the global.asax a database initializer is set that forces recreation of the database every time the application starts up.
Successfully retrieving an entity from a context in a controller action may still cause null reference errors when traversing references even if the references are marked as required (not null in the database). Turning off lazy loading does not make any difference.
This behaviour cannot be reproduced reliably but was observed on two different workstations (XP, 7) using Cassini.
Below are the models. Null reference exception is thrown when trying to access the NewsProvider property of the NewsFeed object. It makes no difference taking off the virtual qualifier.
public class NewsProvider
{
public int Id { get; set; }
[Required(ErrorMessage = "Please enter a name")]
[StringLength(50, ErrorMessage = "The name is too long")]
public string Name { get; set; }
}
public class NewsFeed
{
public int Id { get; set; }
[Required(ErrorMessage = "Please enter a name")]
[StringLength(50, ErrorMessage = "The name is too long")]
public string Name { get; set; }
[Required(ErrorMessage = "Please enter a URL")]
[StringLength(300, ErrorMessage = "The URL is too long")]
public string Url { get; set; }
[Required(ErrorMessage = "Please enter a news provider")]
public virtual NewsProvider NewsProvider { get; set; }
}
This is just a guess, but complex types can NEVER be null. So if you have any reference to a complex type (ICollection) you should initialize them from the Entity constructor.
Example:
public class NewsProvider
{
public int Id { get; set; }
[Required(ErrorMessage = "Please enter a name")]
[StringLength(50, ErrorMessage = "The name is too long")]
public string Name { get; set; }
}
public class NewsFeed
{
public NewsFeed() {
//Never allow NewsProvider to be null
NewsProvider = new NewsProvider();
}
public int Id { get; set; }
[Required(ErrorMessage = "Please enter a name")]
[StringLength(50, ErrorMessage = "The name is too long")]
public string Name { get; set; }
[Required(ErrorMessage = "Please enter a URL")]
[StringLength(300, ErrorMessage = "The URL is too long")]
public string Url { get; set; }
[Required(ErrorMessage = "Please enter a news provider")]
public virtual NewsProvider NewsProvider { get; set; }
}
For more info, here is a great blog post:
http://weblogs.asp.net/manavi/archive/2010/12/11/entity-association-mapping-with-code-first-part-1-one-to-one-associations.aspx