I'm trying out the ServiceStack MVC PowerPack, and am trying the included OrmLite ORM and am trying to get data from a table referenced by a foreign key without any idea how to do so.
In the OrmLite examples that use the Northwind database, for example, would it be possible to return a Shipper object that included the "ShipperTypeName" as a string looked up through the foreign key "ShipperTypeID"?
From http://www.servicestack.net/docs/ormlite/ormlite-overview, I'd like to add the ShipperName field to the Shipper class if possible:
[Alias("Shippers")]
public class Shipper : IHasId<int>
{
[AutoIncrement]
[Alias("ShipperID")]
public int Id { get; set; }
[Required]
[Index(Unique = true)]
[StringLength(40)]
public string CompanyName { get; set; }
[StringLength(24)]
public string Phone { get; set; }
[References(typeof(ShipperType))]
public int ShipperTypeId { get; set; }
}
[Alias("ShipperTypes")]
public class ShipperType : IHasId<int>
{
[AutoIncrement]
[Alias("ShipperTypeID")]
public int Id { get; set; }
[Required]
[Index(Unique = true)]
[StringLength(40)]
public string Name { get; set; }
}
To do this you would need to use Raw SQL containing all the fields you want and create a new Model that matches the SQL, so for this example you would do something like:
public class ShipperDetail
{
public int ShipperId { get; set; }
public string CompanyName { get; set; }
public string Phone { get; set; }
public string ShipperTypeName { get; set; }
}
var rows = dbCmd.Select<ShipperDetail>(
#"SELECT ShipperId, CompanyName, Phone, ST.Name as ShipperTypeName
FROM Shippers S INNER JOIN ShipperTypes ST
ON S.ShipperTypeId = ST.ShipperTypeId");
Console.WriteLine(rows.Dump());
Which would output the following:
[
{
ShipperId: 2,
CompanyName: Planes R Us,
Phone: 555-PLANES,
ShipperTypeName: Planes
},
{
ShipperId: 3,
CompanyName: We do everything!,
Phone: 555-UNICORNS,
ShipperTypeName: Planes
},
{
ShipperId: 4,
CompanyName: Trains R Us,
Phone: 666-TRAINS,
ShipperTypeName: Trains
}
]
Related
Is there a way to change the default {PropertyReference}Id naming convention for references and foreign keys ?
For example, I want to do this :
public class Customer
{
[References(typeof(CustomerAddress))]
public int Id_PrimaryAddress { get; set; } // with a prefix
[Reference]
public CustomerAddress PrimaryAddress { get; set; }
}
instead of that :
public class Customer
{
[References(typeof(CustomerAddress))]
public int PrimaryAddressId { get; set; } // standard
[Reference]
public CustomerAddress PrimaryAddress { get; set; }
}
Thank you
You can't change the code convention of OrmLite's Reference Conventions globally, but you can use the [Alias("DbColumnName")] to map it to a different underlying RDBMS Table column.
Overriding Conventions with Attributes
You're also able to use the Foreign Key and References Attributes as your example does to override the conventions, e.g. you can play with this Live Example on Gistlyn:
public class CustomerAddress
{
[AutoIncrement]
public int Id { get; set; }
public string Address { get; set; }
public string Country { get; set; }
}
public class Customer
{
[AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
[References(typeof(CustomerAddress))]
public int Id_PrimaryAddress { get; set; } // with a prefix
[Reference]
public CustomerAddress PrimaryAddress { get; set; }
}
db.CreateTable<Customer>();
db.CreateTable<CustomerAddress>();
var customer = new Customer
{
Name = "The Customer",
PrimaryAddress = new CustomerAddress {
Address = "1 Home Street",
Country = "US"
},
};
db.Save(customer, references:true);
Where you can load it and its references and view it with:
var c = db.LoadSelect<Customer>(x => x.Name == "The Customer");
c.PrintDump();
Which will output:
[
{
Id: 1,
Name: The Customer,
Id_PrimaryAddress: 1,
PrimaryAddress:
{
Id: 1,
Address: 1 Home Street,
Country: US
}
}
]
We have noticed an anomaly when using "?Fields=" in version 4.0.55 (pre-release on MyGet).
We have an Employee table with three 1:1 relationships - EmployeeType, Department and Title:
public partial class Employee {
[PrimaryKey]
[AutoIncrement]
public int ID { get; set; }
[References(typeof(EmployeeType))]
public int EmployeeTypeID { get; set; }
[References(typeof(Department))]
public int DepartmentID { get; set; }
[References(typeof(Title))]
public int TitleID { get; set; }
.
.
.
}
public class EmployeeType {
[PrimaryKey]
public int ID { get; set; }
public string Name { get; set; }
}
public class Department {
[PrimaryKey]
public int ID { get; set; }
public string Name { get; set; }
[Reference]
public List<Title> Titles { get; set; }
}
public class Title {
[PrimaryKey]
public int ID { get; set; }
[References(typeof(Department))]
public int DepartmentID { get; set; }
public string Name { get; set; }
}
The latest update to 4.0.55 allows related DTOs to be requested using ?Fields= on the query string like this:
/employees?fields=id,firstname,lastname,departmentid,department
Note that the "proper" way to request a related DTO (department) is to also request the foreign key field (departmentid, in this case).
We wondered if there was a way to return all of the Employee table fields and only selected related DTOs, so in testing we found that this request works:
/employees?fields=department
We get back all the Employee table fields plus the related Department DTO - with one strange thing - the Employee's ID field is populated with the Employee's TitleID values.
Specifying the foreign key field in the request fixes that anomaly:
/employees?fields=id,departmentid,department
but we lose all of the other Employee fields.
Is there a way that to get all of the Employee fields and selected related DTOs?
Here is our AutoQuery DTO:
[Route("/employees", "GET")]
public class FindEmployeesRequest : QueryDb<Employee>,
IJoin<Employee, EmployeeType>,
IJoin<Employee, Department>,
IJoin<Employee, Title> {
public int? ID { get; set; }
public int[] IDs { get; set; }
public string UserID { get; set; }
public string[] UserIDs { get; set; }
public int? EmployeeTypeID { get; set; }
public int[] EmployeeTypeIDs { get; set; }
public int? DepartmentID { get; set; }
public int[] DepartmentIDs { get; set; }
public int? TitleID { get; set; }
public int[] TitleIDs { get; set; }
public string LastNameStartsWith { get; set; }
public DateTime[] DateOfBirthBetween { get; set; }
public DateTime[] HireDateBetween { get; set; }
public bool? IsActive { get; set; }
[QueryDbField(Template = "(MONTH({Field}) = {Value})", Field = "DateOfBirth")]
public int? BirthMonth { get; set; }
[QueryDbField(Template = "(DAY({Field}) = {Value})", Field = "DateOfBirth")]
public int? BirthDay { get; set; }
[QueryDbField(Template = "(FirstName LIKE {Value} OR LastName LIKE {Value} OR PreferredName LIKE {Value})", ValueFormat = "%{0}%", Field = "ID")]
public string NameSearch { get; set; }
[QueryDbField(Template = "(FirstName LIKE {Value} OR LastName LIKE {Value} OR PreferredName LIKE {Value} OR Department.Name LIKE {Value} OR Title.Name LIKE {Value})", ValueFormat = "%{0}%", Field = "ID")]
public string BasicSearch { get; set; }
[QueryDbField(Template = "({Field} LIKE {Value})", Field = "EmployeeTypeName", ValueFormat = "%{0}%")]
public string EmployeeTypeSearch { get; set; }
[QueryDbField(Template = "({Field} LIKE {Value})", Field = "DepartmentName", ValueFormat = "%{0}%")]
public string DepartmentSearch { get; set; }
[QueryDbField(Template = "({Field} LIKE {Value})", Field = "TitleName", ValueFormat = "%{0}%")]
public string TitleSearch { get; set; }
}
Support for wildcard custom field lists was added in this commit where you can specify all fields of the primary or joined table by adding a .* suffix, e.g:
?fields=id,departmentid,department,employee.*
It essentially serves as a substitute placeholder which will be replace it with all fields in the specified table.
This change is available from v4.0.55 that's now available on MyGet.
I am new to MVC and i think someone answered this question before , so i apologize for re-posting it.
I've been a form based programmers for years , and now i am working on an MVC project for the first time, last 3 weeks i read a lot of books, articles, tutorials and watched a lot of videos about MVC.
Here is my question:
- I have 3 tables: Tasks, Customer and Employee
Each task has 1 customer and one employee assigned to it. I generated the Tasks table from an existing table i have on a SQL DB , but i followed "Code-First" to create the employee and Customer tables. I am not sure if i did the right relationships between those table. What i want to do is to display all tasks + the userNAME + CustomerName instead of UserID and CustomerID.
Here are my models:
Tasks:
public partial class Tasks
{
public string TaskID { get; set; }
public string Name { get; set; }
public System.DateTime StartDate { get; set; }
public Nullable<System.DateTime> DueDate { get; set; }
public Nullable<int> Complete { get; set; }
public string Description { get; set; }
public Nullable<int> Priority { get; set; }
public string Status { get; set; }
public Nullable<System.DateTime> AssignementDate { get; set; }
public Nullable<System.DateTime> CreationDate { get; set; }
[ForeignKey ("Employee")]
public string EmployeeID { get; set; }
public virtual ApplicationUser _User { get; set; }
[ForeignKey("Customer")]
public string CustomerID { get; set; }
public virtual CustomerModel _Customer { get; set; }
}
Customer:
public class CustomerModel
{
[Key]
public String ID { get; set; }
public String Number { get; set; }
}
Employee
public class EmployeeModel
{
[Key]
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Also How to access the employee first name from my Tasks controller.
Last question: is it ok to mix between models (Some code-first and some DB-first) Or should i follow one pattern.
Thanks a lot
You can use both pattern, but I recommend you my approach that you use CodeFirst, create entites to store data and viewmodels to display data:
public class Task
{
public int TaskID { get; set; }
//your other properties here...
public int EmployeeId { get; set; }
public int UserId { get; set; }
public int CustomerId { get; set; }
}
And in client lawyer, create ViewModel for Task model:
public class TaskViewModel
{
public Task Task { get; set; }
public EmployeeModel Employee { get; set; }
public ApplicationUser User { get; set; }
public CustomerModel Customer { get; set; }
}
In your GetTask() (Or LoadTasks()) method fill this view model:
public TaskViewModel GetTask(int id)
{
TaskViewModel model = new TaskViewModel();
model.Task = _db.GetTaskById(id);
model.Employee = _db.GetEmployeeById(model.Task.EmployeeId);
model.User = _db.GetUserById(model.Task.UserId);
model.Customer = _db.GetCustomerById(model.Task.CustomerId);
return model;
}
And now, you can get all data you want related to a task:
TaskId, TaskName, Created user's name + surname, Employee's name surname, Custemer's name + surname etc..
I'm using EF5.0 (database first) and trying to Update "Company" entity which is a complex type, it contains "Address" entity as navigation property.
I receive a Company DTO object from UI and I map it, using AutoMapper, to Entity object and call objectContext.Save() for saving.
Problem am facing is, "Company" entity values are getting saved but not the "Address" entity. Below are the each object details-
public class CompanyDto
{
public int Id { get; set; }
public string Name { get; set; }
public AddressDto Address { get; set; }
}
with AddressDto as -
public class AddressDto : IDto
{
public int Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string PostCode { get; set; }
}
Company Entity (generated by EF - database first)
public partial class tblCompany
{
public tblCompany()
{
this.tblAddresses = new HashSet<tblAddress>();
}
public int ID { get; set; }
public string CompanyName { get; set; }
public virtual ICollection<tblAddress> tblAddresses { get; set; } //navigation property
}
with Address entity is as follows -
public partial class tblAddress
{
public int ID { get; set; }
public int CaseID { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public string County { get; set; }
public string PostCode { get; set; }
public virtual tblCase tblCase { get; set; }
}
AutoMapper mapping configuration for converting from DTO to entity
Mapper.CreateMap<CompanyDto, tblCase>()
.ForMember(x => x.ID, opt => opt.MapFrom(cd => cd.Id))
.ForMember(x => x.CompanyName, opt => opt.MapFrom(cd => cd.Name))
.AfterMap((s, d) => d.tblAddresses.Add(new tblAddress
{
AddressLine1 = s.Address.Street,
CaseID = s.Id,
City = s.Address.City,
PostCode = s.Address.PostCode
}));
public void Update(CompanyDto company)
{
//TO DO: check if AutoMapper could map address as well.
var companyDao = Mapper.Map<CompanyDto, tblCase>(company);
_companyRepository.Update(companyDao);
_unitOfWork.Save();
}
Thanks in advance
Sai
It's the first time I use Subsonic.
Let say I have those classes :
public class Store
{
public int Id { get; set; }
public String Name { get; set; }
}
public class Employee
{
public int Id { get; set; }
public String Name { get; set; }
}
An employee is related to a store with is hired date. This means that in the database I will have a middle table With StoreId, EmployeeId, StartDate, EndDate
UPDATE
An employee can work to the StoreA from 2009-01-01 to 2009-04-04 and work for StoreB from 2009-04-05 to ... And I don't want that my data table repeat all the information of my employee each time an employee change the store he working for. In this example employee have only a name, but lets say an employee got 10 property (adress, age, gender ...)
How could I achieve that ?
Based on your comment and the updated question it looks like you want something like the following:
public class Store
{
public int Id { get; set; }
public String Name { get; set; }
}
public class StoreEmployee
{
public int Id { get; set; }
public Employee Employee { get; set; }
public Store Store { get; set; }
public DateTime HiredDate { get; set; }
}
public class Employee
{
public int Id { get; set; }
public String Name { get; set; }
}
You'll actually need a many-to-many relationship which will join an Employee record to a Store Record, with a payload of Start and End Dates.
The Objects will look like this:
public class Store
{
public int Id { get; set; }
public String Name { get; set; }
}
public class Employee
{
public int Id { get; set; }
public String Name { get; set; }
public IList<EmploymentTerm> EmploymentTerms { get; set; }
}
public class EmploymentTerm
{
public int Id { get; set; }
public Store Store { get; set; }
public Employee Employee { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
}
Did this freehand so there could be a couple errors.