I'm about to create an ASP.Net Web Application with MVC and EF for the following scenario:
Every month there are new people entering a department in our company. Until now we're using an Excel Spreadsheet to handle common "Workitems" such as granting filesystem permissions etc.
Now I want to handle those requests using a Webapplication but I'm stuck at creating the Model.
There are two different Requesttypes, "JoinRequest" and "ChangeRequest" for people joining the company and employees changing the department. For each request type there are different workitems defined. Those workitems should be displayed in the webapp when the corresponding request is selected. After the data is loaded the user has to enter the data for the workitems.
E.g.
[JoinRequest]
Add new Filesystem Access permission:
[ UNC Path ] [x] Read [ ] Read & Write
Here the user has to enter the UNC Path and the type of Accesslevel (R or RW).
For now I've got the following Model:
public abstract class DbItem {
[Key]
public int Id { get; set; }
public DateTime CreationDate { get; set; }
public DateTime? DeletionDate { get; set; }
public string CreatedBy { get; set; }
public string DeletedBy { get; set; }
public bool IsDeleted => DeletionDate != null;
}
public abstract class Request : DbItem {
public Department NewDepartment { get; set; }
public DateTime BeginDate { get; set; }
public DateTime? EndDate { get; set; }
public ContractType ContractType { get; set; }
public EmployeeType EmployeeType { get; set; }
public string Location { get; set; }
public string ContactUserId { get; set; }
[NotMapped]
public User Contact {
get {
if (!string.IsNullOrWhiteSpace(ContactUserId)) {
var userSearcher = new ActiveDirectoryUserSearcher();
return userSearcher.FindByUserID(ContactUserId);
}
return null;
}
}
public string Phonenumber { get; set; }
//public virtual List<RequestWorkItem> RequestWorkItems { get; set; }
public bool IsFinished { get; set; }
public abstract string GetRequestType();
}
public abstract class WorkItem : DbItem {
[Key]
[ForeignKey("Language")]
public int LanguageId { get; set; }
[NotMapped]
public virtual Language Language { get; set; }
public string WorkItemText { get; set; }
public virtual Category Category { get; set; }
}
public class JoinRequest : Request {
public Person Person { get; set; }
public override string GetRequestType() {
return "New";
}
}
public class FileSystemAccessWorkItem : AccessWorkItem {
public FileSystemAccessRight FileSystemAccessRight { get; set; }
public string FileSystemPath { get; set; }
}
So when a user visits the website a new request has to be created but for every request type a set of workitems has to be loaded from the database. Additionally for every workitem the data the user entered should be saved somehow.
I hope you understand what I'm looking for - If anything is unclear I'll do my best to explain it more precisely
Edit1:
When looking at my Models I think the only think I achived is defining my Requests (so e.g. a JoinRequest contains some specific WorkItems) but how can I achive that a user is able to use this "RequestTemplate" to create a new Request and fill in the data to the corresponding workitems. Do I need additional Models for that? Maybe an example?
Related
I am new to MVC and view models.I have trouble generating a LINQ search query on a related property of my search model. Here is my model of MaterialRequestMaster in domain layer:
public class MaterialRequestMaster : BaseDomain<long>
{
public string RequestCode { get; private set; }
public int UserId { get; private set; }
public GlobalEnums.MaterialRequestStatus Status { get; set; }
public SecurityUser User { get; private set; } //related property
}
and a MaterialRequestMasterSearchViewModel in application layer:
public class MaterialRequestMasterSearchModel
{
public string RequestCode { get; set; }
public GlobalEnums.MaterialRequestStatus Status { get; set; }
public string UserName { get; set; }
public DateTime CreationDate { get; set; }
}
which holds name of the user instead of the user Id ,and I have a service to make where-string of the LINQ query where gets the JSON of search parameters from view.
How do I search MaterialRequestMasters on user name field?
I have these objects:
public class Domain : EntityTypeConfiguration<Domain>, IEntity
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public Guid Guid { get; set; }
public ICollection<Website> Websites { get; set; }
}
public class Website: EntityTypeConfiguration<Website>, IEntity
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Range(1, int.MaxValue)]
public int DomainId { get; set; }
public string Description { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreationDate { get; set; }
[Required]
public Guid Guid { get; set; }
[Required]
public string LanguageIds { get; set; }
public bool AllowToSharedTemplates { get; set; }
public int PublishWebsiteId { get; set; }
[Required]
public string WebsiteUrl { get; set; }
public virtual Domain Domain { get; set; }
}
When I want all the websites I want the connected Domains as well (each website has one domain). But somehow this does not work.
public IList<T> GetAll()
{
IList<T> ret;
using (IocDbContext db = Context.CreateContext())
{
DbSet<T> dbSet = db.Set<T>();
ret = dbSet.ToList();
}
return ret;
}
The CreateContext
public IocDbContext CreateContext()
{
IocDbContext rety= new IocDbContext(_siteType.ConnectionString);
rety.Configuration.ProxyCreationEnabled = true;
return rety;
}
As you can see I have a generic repository. It works fine with just one object, but with navigation properties not. With lazy loading, it does not find the navigation property (domain in this case). I get this error:
The 'ObjectContent`1' type failed to serialize the response body for
content type 'application/json; charset=utf-8'.
When I try to map the DTO to an object:
public static Objects.Website ToModel(this Data.Contexts.Website value)
{
if (value == null)
return null;
return new Website
{
Id = value.Id,
Name = value.Name,
Domain = value.Domain?.ToModel()
};
}
Because you have your context wrapped in a using statement, lazy loading would never work because by the time you leave the GetAll() method, the context has been disposed and the connection to the database has been closed.
As much as lazy loading looks like a great option, I would highly recommend against using it unless you know what you're doing. It's much safer to explicitly load the data you need.
There is a custom object(ex company) and list of custom object (ex employee) which needs to be saved in a BLOB datatype, Below is the piece of code I have tried without success. I have tried DbType.Binary but it did not workout.
Below is the piece of insert query :
sql_cmd.Parameters.Add("#company", DbType.Byte);
sql_cmd.Parameters["#company"].Value = (Company)root.company;
sql_cmd.Parameters.Add("#employees", DbType.Byte);
sql_cmd.Parameters["#employees"].Value = ((List< Employee >))root.employeeList;
Exception :
System.FormatException was unhandled by user code.
Message=Input string was not in a correct format.
Below is the associated classes
class Company
{
public string id { get; set; }
public string name { get; set; }
public List<Package> packages { get; set; }
public string description { get; set; }
}
class Employee
{
public string id { get; set; }
public string name { get; set; }
public object description { get; set; }
public Address address { get; set; }
public Contact contact { get; set; }
public string enterpriseId { get; set; }
public object createdDate { get; set; }
public object modifiedDate { get; set; }
}
If you are using Sqlite.net-PCL you can store an entire object. But not in blob type.
Also you must have a separate table for 'package' objects. you can add a company id property to the package object so you can find the items easily. Also it has a cleaner syntax.
db.CreateTable<Company>();
db.CreateTable<package>();
db.InsertAll(AlistOfCompanies);
I've created a simple .NET backend mobile azure service in C#. I have the mobile service up and running (all it's doing currently is working with your normal CRUD on a single table). The problem I'm having is that the PATCH/UPDATE will not do as it says. I can do everything else I've tried, SELECT, INSERT, DELETE, but I've been unable to update data.
When I debug into the block of code that calls UpdateAsync, the patch.GetEntity()..... always has the values NULL or zeroed out or day one datetimes, like it's not passing along the property values of what I'm trying to update. The only value I ever have is the correct id. Below I tried to strip out some of the code I have, I used some of what was in the first few tutorials on the Azure website.
I have a Data Object:
public class AdminLookupDATA: EntityData
{
public string description { get; set; }
public int lookuptype { get; set; }
public int priority { get; set; }
public bool inactive { get; set; }
public DateTime createdate { get; set; }
public DateTime editdate { get; set; }
}
I have a DTO:
public class AdminLookupDTO
{
public string id { get; set; }
public string description { get; set; }
public int lookuptype { get; set; }
public int priority { get; set; }
public bool inactive { get; set; }
public DateTime createdate { get; set; }
public DateTime editdate { get; set; }
}
I have a Model:
public class AdminLookupModel
{
public string Id { get; set; }
public string description { get; set; }
public int lookuptype { get; set; }
public int priority { get; set; }
public bool inactive { get; set; }
public DateTime createdate { get; set; }
public DateTime editdate { get; set; }
}
My PATCH inside my controller:
public Task<AdminLookupDATA> PatchAdminLookupDATA(string id, Delta<AdminLookupDATA> patch)
{
return UpdateAsync(id, patch);
}
Also, I have the same issue if I try to run the PATCH function directly from the browser in the "try it out" section, so it's something I have configured wrong within the service project itself. Any suggestions would be greatly appreciated.
Thanks,
Rob
Your property names must start with a capital letter.
Otherwise configure the CamelCasePropertyNamesContractResolver as indicated here:
http://odetocode.com/blogs/scott/archive/2013/03/25/asp-net-webapi-tip-3-camelcasing-json.aspx
code snippet
var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
settings.Formatting = Formatting.Indented;
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
I'm encountering an issue using Silverlight4, Ria Services and Entity Framework.
From my sl client I try to get some data through ria services, in my domainService class this method gets called:
public IQueryable<LastMinuteWachtLijstPromotie> GetLastMinuteWachtLijstPromoties(){
IQueryable<LastMinuteWachtLijstPromotie> list = (IQueryable<LastMinuteWachtLijstPromotie>)this.ObjectContext.LastMinuteWachtLijstPromoties.Include("Promotie");
return (from LastMinuteWachtLijstPromotie lwmp in list where lwmp.Actief select lwmp);
}
when I check the contents of the list, in debug mode, it's filled with objects of type LastMinuteWachtLijstPromotie.
these objects have a navigation property to an Object named Promotie.
And i can access the properties of these Promotie objects.
On the silveright client however a method gets invoked when loading is complete:
public void OnLoadEntitiesCompleted(ServiceLoadResult<T> result) {
}
In this method I get all the requested LastMinuteWachtLijstPromotie objects as expected, the property
Promotie however is null.
I have set the [Include] tag on the property Promotie in the auto generated metadata class
and I use the .Include("Promotie")
These same methods are used for different objects from my Domain Model, this works perfectly.
Also, I cannot seem to find differences in the .edmx file with the database mappings and navigation properties.
Has anyone encountered the same issue or know a solution for it?
the metadata classes:
[MetadataTypeAttribute(typeof(LastMinuteWachtLijstPromotie.LastMinuteWachtLijstPromotieMetadata))]
public partial class LastMinuteWachtLijstPromotie
{
// This class allows you to attach custom attributes to properties
// of the LastMinuteWachtLijstPromotie class.
//
// For example, the following marks the Xyz property as a
// required property and specifies the format for valid values:
// [Required]
// [RegularExpression("[A-Z][A-Za-z0-9]*")]
// [StringLength(32)]
// public string Xyz { get; set; }
internal sealed class LastMinuteWachtLijstPromotieMetadata
{
// Metadata classes are not meant to be instantiated.
private LastMinuteWachtLijstPromotieMetadata()
{
}
public int AlertId { get; set; }
public string ArtikelNummer { get; set; }
public Nullable<int> ArtikelVariant { get; set; }
public int LastMinuteWachtLijstPromotieId { get; set; }
[Include]
public Promotie Promotie { get; set; }
public int PromotieArtikelId { get; set; }
public int PromotieId { get; set; }
public bool Actief { get; set; }
public DateTime Aanmaakdatum { get; set; }
}
}
[MetadataTypeAttribute(typeof(Promotie.PromotieMetadata))]
public partial class Promotie
{
// This class allows you to attach custom attributes to properties
// of the Promotie class.
//
// For example, the following marks the Xyz property as a
// required property and specifies the format for valid values:
// [Required]
// [RegularExpression("[A-Z][A-Za-z0-9]*")]
// [StringLength(32)]
// public string Xyz { get; set; }
internal sealed class PromotieMetadata
{
// Metadata classes are not meant to be instantiated.
private PromotieMetadata()
{
}
public string ActieType { get; set; }
public string AssortimentsManagerNaam { get; set; }
public string AssortimentsManagerTeamIds { get; set; }
[Display(Name = "Commerciele tekst")]
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Nokavision.ReclameFolder.UI.Web.Resources.ValidationResources))]
public string CommercieleTekst { get; set; }
[Display(Name = " ")]
public string CommercieleTekstDetails { get; set; }
[Include]
public Frame Frame { get; set; }
public Nullable<int> FrameId { get; set; }
public Nullable<DateTime> LastMinuteWijzigingsDatum { get; set; }
public string Opmerkingen { get; set; }
[Display(Name = "Op wachtlijst")]
public Nullable<bool> OpWachtLijst { get; set; }
//public Nullable<int> PromotieCopyId { get; set; }
public int PromotieId { get; set; }
[Include]
public EntityCollection<PromotieLeverancier> PromotieLeveranciers { get; set; }
[Include]
public EntityCollection<PromotieMutatie> PromotieMutaties{ get; set; }
//public Nullable<int> PromotieOrigineleId { get; set; }
[Include]
public EntityCollection<PromotieSymbool> PromotieSymbolen { get; set; }
public string Status { get; set; }
[Display(Name = "Promotie inhoud")]
public string PromotieInhoud { get; set; }
[Display(Name = "Promotie eenheid")]
public string PromotieEenheid { get; set; }
[Display(Name = "Promotie prijs")]
public decimal PromotiePrijs { get; set; }
}
}
Add the Composition attribute to the property Promotie property of the LastMinuteWachtLijstPromotieMetadata class. Then it should work.
public partial class LastMinuteWachtLijstPromotie {
internal sealed class LastMinuteWachtLijstPromotieMetadata{
[Include]
[Composition]
public Promotie Promotie { get; set; }
}
}
I know this is an older thread and it may well have been answered elsewhere but I just stumbled upon it and since nobody has provided a link or a better answer.
I'm currently using Silverlight 5 and this is what worked for me (I think the process is the same in SL4 IIRC).
When propegating navigation properties to the client you need to tell RIA services that there is a relationship somewhere using the [Key] and [Association] attributes, this, not unlike the entity framework just describes how to map the relationship to the proper object.
First the metadata classes:
[MetadataTypeAttribute(typeof(Category.CategoryMetadata))]
public partial class Category
{
internal sealed class CategoryMetadata
{
private CategoryMetadata() {
}
[Key]
public int Id { get; set; }
public string NAME { get; set; }
[Association("CategoryToProducts", "Id", "CAT")]
[Include]
public EntityCollection<Product> Products { get; set; }
}
}
[MetadataTypeAttribute(typeof(Order.OrderMetadata))]
public partial class Order
{
internal sealed class OrderMetadata
{
// Metadata classes are not meant to be instantiated.
private OrderMetadata() {
}
[Key]
public int Id { get; set; }
public int PRODID { get; set; }
public DateTime DATE { get; set; }
public bool DONE { get; set; }
public int QTY { get; set; }
[Association("OrderToProduct", "PRODID", "Id", IsForeignKey = true)]
[Include]
public Product Product { get; set; }
}
}
[MetadataTypeAttribute(typeof(Product.ProductMetadata))]
public partial class Product
{
internal sealed class ProductMetadata
{
private ProductMetadata() {
}
[Key]
public int Id { get; set; }
public int CAT { get; set; }
public string NAME { get; set; }
public string DESC { get; set; }
public decimal PRICE { get; set; }
public int QTY { get; set; }
public long UPC { get; set; }
[Association("ProdToCat", "CAT", "Id", IsForeignKey = true)]
[Include]
public Category Category { get; set; }
[Association("ProductToOrders", "Id", "PRODID")]
[Include]
public EntityCollection<Order> Orders { get; set; }
}
}
Now we need to tell RIA services we want it to load the association:
(Note: Intellisense says it's a dot separated list of property names to include, however I tried something like .Include("Category.SubCategory") and this failed with an exception... though .Include("Category").Include("SubCategory") worked like a charm!)
public IQueryable<Product> GetProducts() {
return this.ObjectContext.Products.Include("Category");
}
I can now access my "Category" property from the Silverlight client and it is not NULL :)
Same as SilverX: just had the issue, solved it and thought it could be useful to someone.
I too had all the configuration stuff correct ([Include] for RIA S, Include() for EF) but a navigation property was still null on the Silverlight side.
Turns out the domain service method was using the [Invoke] attribute (and returning a IEnumerable<T>). Removing this attribute solved the issue.
(just for the record, [Invoke] was being used because the method had a List<Entity> parameter)