How to grab a property object from DB - database

I'm having some doubts, maybe newbie doubts but I just got into ASP.NET MVC 4
Basically I would like to know the correct way of grabbing details of an Object inside a model.
In this case Image inside Contractor.
Model:
public class Contractor {
[Key]
public int ContractorID { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Address { get; set; }
public Image Avatar { get; set; }
}
public class Image {
[Key]
public int ImageID { get; set; }
[Required]
public string File_name { get; set; }
[Required]
public byte[] File_data { get; set; }
}
public class DATACRUD : DbContext {
public DbSet<Contractor> Companies { get; set; }
public DbSet<Image> Images { get; set; }
}
Controller:
private DATACRUD db = new DATACRUD();
public ActionResult GetContractorAvatar(int id)
{
Contractor contractor = db.Contractors.Find(id);
if (contractor == null)
{
return HttpNotFound();
}
Image avatar = contractor.Avatar;
Problem 1)
avatar == null, but is not suppose to be because when I created the object Contractor, I added the image sucessfully (I checked in the DB and it is there)
The solution I'm seeing is instead of having Image property in Contractor.cs model, I would just put a string property with the image key.
Problem 2)
Even If could grab the image key like I said in the previous problem, when I pass my mouse in Debug mode over
private DATACRUD db = new DATACRUD ();
db.Images is also empty...
return File(avatar.File_data, "image");
}

Because you haven't defined your Image navigation property as virtual, you will have to eager load the Image when loading a Contractor:
db.Contractors.Include("Avatar").SingleOrDefault(c => c.ContractorID == id);
OR
// using System.Data.Entity;
db.Contractors.Include(c => c.Avatar).SingleOrDefault(c => c.ContractorID == id);

Related

Business Rule errors not going away when data is valid

I am using Orc.FluentValidation and I have:
[ValidatorDescription(nameof(Customer), ValidationResultType.Error,
Orc.FluentValidation.ValidationType.BusinessRule)]
public class CustomerBusinessRuleValidator : AbstractValidator<Customer>
{
public CustomerBusinessRuleValidator()
{
RuleFor(x => x.Addresses).Must(x => x != null && x.Count > 0 && x.Any(add => add.IsCurrent))
.WithMessage("Customer object is required to have at least 1 current address.");
}
}
CustomerAddress
public class CustomerAddress : Entity
{
[DomainSignature] public Address Address { get; set; }
[DomainSignature] public Lookup AddressType { get; set; }
[DomainSignature] public bool IsCurrent { get; set; }
}
Customer
public class Customer : Entity
{
[DomainSignature]
public string Code { get; set; }
public Gender Gender { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public DateTime DateOfBirth { get; set; }
public Lookup PlaceOfBirth { get; set; }
public string PhoneNumber { get; set; }
public string Email { get; set; }
public ICollection<CustomerAddress> Addresses { get; set; }
public Lookup Occupation { get; set; }
public IdDocument Id1 { get; set; }
public IdDocument Id2 { get; set; }
}
On the View even after a CustomerAddress with IsCurrent = true is added for the Customer, the message still shows. Also, I am not sure why some field-bound controls show the error and others not _this is not a field validation rule.
Is there like a method call to be done after adding the CustomerAddress to the Addresses collection?
i.imgur.com/eecAFuJ.png
Make sure you raise a property changed on the whole collection for error validation (e.g. RaisePropertyChanged(nameof(MyCollection)), otherwise the UI can't update the validation results.
Also, I am not sure why some field-bound controls show the error and
others not _this is not a field validation rule.
This is probably because of the default styles you are using. For most of the controls, Orchestra creates an error template (decorator), but not every control had this. We've been working on adding these last week, so I recommend to try out the latest alpha of Orchestra & Orc.Controls.
Also make sure to set ValidateOnDataErrors and NotifyOnValidationErrors on the binding to show the validation in the UI.

How to to make entity relationships in WEB API database?

I'm making a task management tool using AngularJS for the frontend and ASP.NET WEB API 2 for the backend. I have two entities in the database, a "Task" and a "Type". Each task has one type associated. The user fills a form when he can create a new task, and he has to select a type for that task.
Here's the C# code:
// KBTM_Task.cs file
public class KBTM_Task
{
public int ID { get; set; }
public string TaskID { get; set; } // User defined ID
public string Title { get; set; }
public string Description { get; set; }
}
// KBTM_Type.cs file
public class KBTM_Type
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
So my question is: how do I "connect" the two in the database? What I mean is, let's say I want to POST data to the database. I have to make two POSTs, right? One for the Task and one for the Type, since they're two separate entities.
But since they're stored with two different IDs, how do I know that a certain task has a certain type? In other words, if I send a GET request to KBTM_Task, how do I get the type of that task?
Modify your KBTM_Task entity to include the Type Id and foreign key relationship
public class KBTM_Task
{
public int ID { get; set; }
public string TaskID { get; set; } // User defined ID
public string Title { get; set; }
public string Description { get; set; }
public int TypeID { get; set; }
[ForeignKey("TypeID")]
public virtual KBTM_Type Type { get; set; }
}
This way when you get the data from the API your task object will already include the key ("TypeID") that can be updated and related object ("Type") that you can access its properties (Name, Description, ...).
When you update TypeID on the client object (model) you can simply push the updated task object to the API using $http.put() to handle the database update.
1) Add foreign key using fluent api (or data annotation)
// KBTM_Task.cs file
public class KBTM_Task
{
public int ID { get; set; }
public string TaskID { get; set; } // User defined ID
public string Title { get; set; }
public string Description { get; set; }
public int KBTM_TypeID {get;set}
public virtual KBTM_Type {get; set}
}
// KBTM_Type.cs file
public class KBTM_Type
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public KBTM_Task KBTM_Task { get; set;}
}
Add the following in the class inheriting from DbContext
public class KbtmContext : DbContext
{
...
//public virtual DbSet<KBTM_Task> KbtmTasks {get; set;}
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Configure KBTM_TypeID as FK for KBTM_Task
modelBuilder.Entity<KBTM_Task>()
.HasRequired(k => k.KBTM_Type)
.WithRequiredPrincipal(ad => ad.KBTM_Task);
}
}
2) If exposing the entity class in API response or request then you need to exclude navigation property from being serialized.
// KBTM_Task.cs file
public class KBTM_Task
{
...
[JsonIgnore]
public virtual KBTM_Type Type { get; set; }
}
To use the [JsonIgnore] atttribute use Install-Package Newtonsoft.Json in package manager console.(One of the popular solutions to manage serialization)

MVC Invalid object name 'dbo.Staffs' error

I got the error Invalid object name 'dbo.Staffs'. but I'm not sure why. I actually deleted and recreated my database with EF because previously I had other errors. But I'm quite sure I recreated it correctly because I've done it in the same way for other programs and it works fine.
.edmx database diagram
Controller
private StaffPortalDBEntities1 db = new StaffPortalDBEntities1();
SqlConnection cnn = new SqlConnection(ConfigurationManager.ConnectionStrings["StaffPortalDBConnectionString"].ConnectionString);
[Authorize]
public ActionResult Index()
{
var userEmail = User.Identity.Name;
var model = db.Staffs.Where(i => i.Email == userEmail).Include("Histories").Include("CurrentApplications").FirstOrDefault();
return View(model);
}
I got the error is for the line var model = db.Staffs.Where(i => i.Email == userEmail).Include("Histories").Include("CurrentApplications").FirstOrDefault();
Generated Staff class
public partial class Staff
{
public Staff()
{
this.Histories = new HashSet<History>();
this.CurrentApplications = new HashSet<CurrentApplication>();
}
public int StaffID { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public Nullable<decimal> AllocatedLeave { get; set; }
public Nullable<int> BalanceLeave { get; set; }
public virtual ICollection<History> Histories { get; set; }
public virtual ICollection<CurrentApplication> CurrentApplications { get; set; }
}
Try this:
var model = db.Staffs.Where(i => i.Email == userEmail).Include(x=>x.Histories).Include(x=>x.CurrentApplications).FirstOrDefault();

Web ApI Entity Framework (Code First) Value not appearing in database

My database will run correctly, and I can input the data manually via SQL Server, however, when I try and pass the value in via my API (testing using Postman), the value won't pass into the database, it appears as "NULL".
I have a reports and a bookings tables.
This is the code for the reports:
public class Report
{
public Report()
{
Injuries = new List<Injury>();
this.Bookings = new HashSet<Booking>();
}
public int Id { get; set; }
public string Club1 { get; set; }
public string Club2 { get; set; }
public virtual ICollection<Injury> Injuries { get; set; }
public virtual ICollection<Booking> Bookings { get; set; }
}
Bookings:
public class Booking
{
//public Booking()
//{
// Reports = new List<Report>();
//}
public int Id { get; set; }
public string Club { get; set; }
public string PlayerName { get; set; }
public string PlayerNumber { get; set; }
public string Reason { get; set; }
public string Description { get; set; }
//public int? Report_Id { get; set; }
public Nullable<int> Report_Id { get; set; }
public virtual Report Report { get; set; }
//public virtual ICollection<Report> Reports { get; set; }
}
Controller:
//POST: api/Reports
[ResponseType(typeof(Report))]
public async Task<IHttpActionResult> PostReport(Report report)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Reports.Add(report);
await db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new { id = report.Id }, report);
}
I put the test information via Postman:
I'm not sure why Report_Id is showing as it's not required, however, Report_Id1 is the field that is connecting the Report and Booking together.
Since your foreign key doesn't follow convention (ReportId), you need to use the annotation [ForeignKey] or a fluent api configuration:
modelBuilder.Entity<Booking>()
.HasRequired(b => b.Report)
.WithMany(b => b.Bookings)
.HasForeignKey(p => p.Report_Id);
That is why EF is adding the second Report_ID1. https://msdn.microsoft.com/en-us/data/hh134698.aspx

How to pass arrays from model to view?

I'm just learning ASP.NET MVC 3, And recently I tried a lot of times to pass arrays/lists/ICollections etc. but couldn't. everytime the list was empty.
For example, the current project:
Model:
public class Video
{
public int VideoID { get; set; }
public string Name { get; set; }
public ICollection<string> Tags { get; set; }
}
Initializer - Seed:
protected override void Seed(DatabaseContext context)
{
var videos = new List<Video>
{
new Video {
Name = "Video01",
Tags = new List<string> { "tag1", "tag2" },
};
videos.ForEach(s => context.Videos.Add(s));
context.SaveChanges();
base.Seed(context);
}
In the view: I do get the Name property, but the Tags are completely empty.
In the debug I get Tags - Count: 0.
This is not the first time it happens to me, to be honest it happens every single time when I try to pass those kind of stuff. a bit of info about the project:
ASP.NET MVC 3, Entity-Framework:Code First, SqlServerCe.4.0.
Crean an entity Tag
public class Video
{
public int VideoID { get; set; }
public string Name { get; set; }
public ICollection<Tag> Tags { get; set; }
}
public class Tag
{
public int TagId { get; set; }
public int VideoId { get; set; }
public string TagText { get; set; }
}
or store tags to one field separated with comma /semicolon or whatever fits for your solution
By default Entity Framework doesn't load associations of an entity, you need to specify it explicitly:
var videos = context.Videos.Include("Tags");

Resources