dealing with property that does not map directly onto column on the database - petapoco

I have the following tables
Client Table and Product Table
ID
Name
ClientProduct Table
ID
ClientID
ProductID
Product class
private int id;
public int ID
{
get { return id; }
set { id = value; }
}
protected string name;
public Product () { }
public Product (string name)
{
this.name = name;
}
public Product (string name)
{
this.name = name;
}
public string Name
{
get { return name; }
set { name = value; }
}
Client class
private int id;
public int ID
{
get { return id; }
set { id = value; }
}
protected string name;
public Client () { }
public Client (string name)
{
this.name = name;
}
public Client (string name)
{
this.name = name;
}
public string Name
{
get { return name; }
set { name = value; }
}
ClientProduct class
protected Client client;
protected Product product;
public ClientProduct () { }
public ClientProduct (Client client, Product product)
{
this.client= client;
this.product= product;
}
public Client client {
get { return client; }
set { client= value; }
}
public Product product {
get { return product; }
set { product= value; }
}
How can I do the following in petaPOCO?
public static System.Collections.Generic.IList<ClientProduct> LoadForClient(Client client)
{
if (null != client)
return Load("ClientID = " + client.ID);
else
return null;
}
such that I can have list of all products for that client that I will later used in my view as
private void LoadProducts(Client client )
{
Products = ClientProduct.LoadForClient(client)
.Select(x => x.Product.Name)
.OrderBy(x => x).ToArray();
}

The 1:M and M:1 relationships seem like what you're after
http://www.toptensoftware.com/Articles/115/PetaPoco-Mapping-One-to-Many-and-Many-to-One-Relationships
You can define a custom relator callback; Brad's example for two tables (if your products mapped directly to the client) would look something like this:
var posts = db.Fetch<Product, Client, ClientProduct>(
(p,c)=> { p.client_obj = c; return p; },
#"SELECT * FROM Product
LEFT JOIN Client ON Product.clientId = Client.id ORDER BY Product.clientId
");
I realize your dealing with a M:M relationship so you would need to update the above to map across the three objects, but the concept is the same. The key is that your 3rd argument in the call (ClientProduct) represents the joined row, and you can then reference the Client and/or Products directly from the single list.

Related

How can I count total item in an object/record and count only the value = true

var obj = (from r in db.Module_Completion
.Where(r => r.star_id == User.Identity.Name)
select new
{
r.adv_stud_success,
r.important_policies,
r.technology,
r.finances,
r.resources,
r.student_life,
r.next_steps
}).FirstOrDefault();
obj = {true, false, false , true,...};
This is only one record that I query from database by using Linq
The reason is I would like to display Finsished 2 of 7 , that is why I need to count items in a record.
Thank you in advance!
public partial class Module_Completion
{
public int module_completionId { get; set; }
[StringLength(10)]
public string star_id { get; set; }
public bool adv_stud_success { get; set; }
public bool important_policies { get; set; }
public bool technology { get; set; }
public bool finances { get; set; }
public bool resources { get; set; }
public bool student_life { get; set; }
public bool next_steps { get; set; }
}
After I can store numbers in variable, then I would like to display like this"Finished 2 of 7"
So Every ModuleCompletion contains several Boolean properties. If the value of such a property is true, you consider the item to be "finished".
You want to count the number of finished items in a ModuleCompletion.
The proper method would be to add a property to class ModuleCompletion.
public int FinishedCount => ...
If you can't do this, for instance because ModuleCompletion represents the columns of a table in a database, then consider to add an extension method. If you are not familiar with extension methods, read Extension Methods demystified
public static int CountFinished(this ModuleCompletion moduleCompletion)
{
// TODO: implement
}
Usage would be:
ModuleCompletion x = ...
int finished = x.CountFinished();
This would work if your ModuleCompletion is in local process. However, if you want to do this database side (as queryable), this won't work: your database wouldn't know method CountFinished.
If you want to let the database do this, you could change your Select method:
int finishedCount = db.ModuleCompletions
.Where(completion => completion.star_id == User.Identity.Name)
.Select(completion =>
completion.adv_stud_success ? 1 : 0 +
completion.important_policies ? 1 : 0 +
completion.technology : 1 : 0 +
...)
.FirstOrDefault();
This looks rather ugly. Luckily we can create an extension method of IQueryable<ModuleCompletion>, such that you can use it as any other LINQ method:
public static IQueryable<int> ToFinishedCount(this IQueryable<ModuleCompletion> moduleCompletions)
{
return moduleCompletions.Select(completion =>
completion.adv_stud_success ? 1 : 0 +
completion.important_policies ? 1 : 0 +
completion.technology : 1 : 0 +
...);
}
This query can be translated into a language that your DBMS understands. Usage would be much easier to understand, much easier to reuse, unit test and modify:
int finishedCount = db.ModuleCompletions
.Where(completion => completion.star_id == User.Identity.Name)
.ToFinishedCount()
.FirstOrDefault();
My solution involves 2 parts first. Create a ViewModel to get the number of completed object that associates with the class that goes:
public class ModuleCompletesVM
{
public Module_Completion Module_Completion { get; set; }
public int Completed { get
{
return (Convert.ToInt32(Module_Completion.stud_success) +
Convert.ToInt32(Module_Completion.important_policies) +
Convert.ToInt32(Module_Completion.technology) +
Convert.ToInt32(Module_Completion.finances) +
Convert.ToInt32(Module_Completion.resources) +
Convert.ToInt32(Module_Completion.next_steps) +
Convert.ToInt32(Module_Completion.student_life));
}
}
}
Note that this View Model would calculate the number of completed subject of each Module_Completion Class and then from your controller. You just need to do something like this
var model= from s in db.Module_Completion
select new ModuleCompletesVM
{
Module_Completion = s
};
You can also achieve this by creating a function in SQL database as well. Another piece of advice is that, do consider stop using underscrore in your data table and data field. Follow the latest convention, the next person who take over your code will appreciate that.
I have an approach where you can have the total finished as property. Here is an example
public partial class Module_Completion
{
private bool _adv_stud_success;
private bool _important_policies;
private bool _technology;
private bool _finances;
private bool _resources;
private bool _student_life;
private bool _next_steps;
public int module_completionId { get; set; }
[StringLength(10)]
public string star_id { get; set; }
public bool adv_stud_success
{
get { return _adv_stud_success; }
set {
_adv_stud_success = value;
if (_adv_stud_success)
{
total_finsihed += 1;
}
}
}
public bool important_policies
{
get { return _important_policies; }
set
{
_important_policies = value;
if (_important_policies)
{
total_finsihed += 1;
}
}
}
public bool technology
{
get { return _technology; }
set
{
_technology = value;
if (_technology)
{
total_finsihed += 1;
}
}
}
public bool finances
{
get { return _finances; }
set
{
_finances = value;
if (_finances)
{
total_finsihed += 1;
}
}
}
public bool resources
{
get { return _resources; }
set
{
_resources = value;
if (_resources)
{
total_finsihed += 1;
}
}
}
public bool student_life
{
get { return _student_life; }
set
{
_student_life = value;
if (_student_life)
{
total_finsihed += 1;
}
}
}
public bool next_steps
{
get { return _next_steps; }
set
{
_next_steps = value;
if (_next_steps)
{
total_finsihed += 1;
}
}
}
/* This property is storing the finished count */
/* using System.ComponentModel.DataAnnotations.Schema; */
[NotMapped]
public int total_finsihed { get; set; }
}
After that you can do the following
var obj = (from r in db.Module_Completion
.Where(r => r.star_id == User.Identity.Name)
select new
{
r.total_finsihed
}).FirstOrDefault();
/* if the technology, finance, resources are true then */
/* obj = {3}; */

RavenDB trouble adding wherein to spatial intersect query

I have an object Partner that looks like this:
public class Partner
{
public double Latitude { get; set; }
public double Longitude { get; set; }
public string ServiceKeyIds { get; set; }
public double WorkingRadius { get; set; }
public float Rating { get; set; }
}
I then have a projection LocalPartner that looks like this:
public class LocalPartner : Partner
{
public string WorkingRadiusShape { get; set; }
}
My index PartnersByLocation looks like this:
public class PartnersByLocation : AbstractIndexCreationTask<Partner,LocalPartner>
{
public PartnersByLocation()
{
Map = partners => from doc in partners
where doc.ServiceKeyIds != null
select new
{
doc.ServiceKeyIds,
WorkingRadiusShape = string.Format("Circle({0},{1}, d={2})", doc.Latitude, doc.Longitude, doc.WorkingRadius)
}.Boost((float)doc.Rating);
Spatial(x => x.WorkingRadiusShape, options => options.Geography.Default());
Index(x => x.ServiceKeyIds, FieldIndexing.NotAnalyzed);
}
}
I try to query the index as follows:
public LocalPartnerList GetNearbyPartners(double lat, double lng, string serviceIds, double rad = 25, int page = 0, int resultsPerPage = 10)
{
RavenQueryStatistics stats;
var point = string.Format(CultureInfo.InvariantCulture, "POINT ({0} {1})", lng, lat);
var query = session.Advanced.LuceneQuery<LocalPartner, PartnersByLocation>().Statistics(out stats).Spatial(x => x.WorkingRadiusShape, c => c.Intersects(point));
if (serviceIds != null && serviceIds.Any())
{
query = query.AndAlso().WhereIn("ServiceKeyIds", serviceIds.SafeSplit());
}
var raw = query.ToString();
query = query.Skip(page * resultsPerPage).Take(resultsPerPage);
var result = new LocalPartnerList();
result.LocalPartners = query.SelectFields<LocalPartner>().ToList();
result.Results = stats.TotalResults;
result.Page = page;
result.NumberPages = (int)Math.Ceiling((double)result.Results / (double)resultsPerPage);
result.Radius = (int)rad;
return result;
}
This query works if I call the method and serciceIds is null. It returns the expected results, but as soon as I apply the .AndAlso().WhereIn() clause the query returns an empty set.
I am certain that there are matching records. I should note that the ServiceKeyIds property of Partner holds a string of comma-separated strings, and the serviceIds passed to the method is the same, and SafeSplit() is an extension method that returns an array of strings.

After successfully adding child entity with parent reference, child does not show under parent resource

I have two entities, Shelf and Book. A Shelf can have multiple Books (the relationship is bi-directional). I've exposed both of these as JpaRepositories.
Here's the issue:
I create a shelf by posting { "name":"sci-fi" } to /shelves.(success)
I create a book for that shelf by posting { "name":"mybook", "shelf":"localhost:8080/shelves/1" } to /books. (success)
When I get the book I just created at /books/1, it has the correct link to the parent shelf.
But when I go to shelves/1/books, I get an empty result, { }!
Any ideas what I might be missing?
Right now I've constructed a workaround by explicitly adding the book to its shelf in a beforeCreate event, but it seems like this should be totally unnecessary. (It does fix the problem, however.)
#HandleBeforeCreate(Book.class)
public void handleCreate(Book book) {
// why is this necessary?
book.getShelf().getBooks().add(book);
}
Here are the entity classes:
#Entity
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
#ManyToOne
private Shelf shelf;
public Shelf getShelf() {
return shelf;
}
public void setShelf(Shelf shelf) {
this.shelf = shelf;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Book other = (Book) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
#Entity
public class Shelf {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
#OneToMany
private List<Book> books = new ArrayList<Book>();
public List<Book> getBooks() {
return books;
}
public void setBooks(List<Book> books) {
this.books = books;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Shelf other = (Shelf) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
I'm using Spring Boot 1.1.8.
In your Shelf entity, add the mappedBy = "self" property to the #OneToMany annotation in books:
#OneToMany(mappedBy = "self")
private List<Book> books = new ArrayList<Book>();
This will auto populate the list of books with the books whose reference to self matches.
I think you need to update shelf to add new book you created as a last step. This is because you are using bi-directional relationship and shelf has no idea about books till you update it with the books it should hold.

How to assign value to Address , Country and City

Here is classes
-Person
-User
-City
-Country
-Address
Person has complex properties of (Address),
Address has complex Properties of (Country , City)
Class User inherited from Person class
scenario:-
I want to create a signup view inwhich i want to assign values to Address , country , city. How can i do it.
Below is the detail of classes
public class Person
{
public Person()
{ }
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private Gender gender;
public virtual Gender Gender
{
get { return gender; }
set { gender = value; }
}
private ICollection<ContactNumber> contactNumber;
public virtual ICollection<ContactNumber> ContactNumber
{
get { return contactNumber; }
set { contactNumber = value; }
}
private Address address;
public virtual Address Address
{
get { return address; }
set { address = value; }
}
private DateTime dateOfBirth;
public DateTime DateOfBirth
{
get { return dateOfBirth; }
set { dateOfBirth = value; }
}
private string picture;
public string Picture
{
get { return picture; }
set { picture = value; }
}
}
public class User : Person
{
public User() : base()
{ }
private ICollection<Role> roles;
public virtual ICollection<Role> Roles
{
get { return roles; }
set { roles = value; }
}
private int id;
public int Id
{
get { return id; }
set { id = value; }
}
private string email;
[Required()]
[RegularExpression(#"\w+([-+.']\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*")]
[Display(Name = "Email Address")]
public string Email
{
get { return email; }
set { email = value; }
}
private string loginId;
[Required()]
[Display(Name = "Login")]
public string LoginId
{
get { return loginId; }
set { loginId = value; }
}
private string password;
[Required()]
[Display(Name = "Password")]
[DataType(DataType.Password)]
public string Password
{
get { return password; }
set { password = value; }
}
private string repassword;
[Required()]
[Display(Name = "Confirm Password")]
[Compare("Password")]
public string Repassword
{
get { return repassword; }
set { repassword = value; }
}
private string secretQuestion;
[Required()]
[Display(Name = "Secret Question")]
public string SecretQuestion
{
get { return secretQuestion; }
set { secretQuestion = value; }
}
private string secretAnswer;
[Required()]
[Display(Name = "Answer")]
public string SecretAnswer
{
get { return secretAnswer; }
set { secretAnswer = value; }
}
private string photoUrl;
[Display(Name = "Image")]
public string PhotoUrl
{
get { return photoUrl; }
set { photoUrl = value; }
}
}
public class Country
{
public Country()
{ }
private int id;
public int Id
{
get { return id; }
set { id = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
//private string flagUrl;
}
public class City
{
public City()
{ }
private int id;
public int Id
{
get { return id; }
set { id = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private Country country;
public virtual Country Country
{
get { return country; }
set { country = value; }
}
}
Thanx in Advance.
If you right click on your action method for your signup page in your controller and select Add View In the dialog that appears you can choose to make the view strongly typed. Select your User class and visual studio will scaffold a lot of the code needed.
If you need more help in working with MVC here is a good place to start.

NHibernate - Is it possible to map columns into collection composite objects

Using NHibernate is it possible to map columns in a table to a collection of objects.
For example if I have a very badly designed database table with columns as such:
ClientID
ClientName
First_AmountPaid
Second_AmountPaid
Third_AmountPaid
Fourth_AmountPaid
Is it possible to map this to the following class structure where First_AmountPaid through to Fourth_AmountPaid have their own class implementation?
public class Client
{
public int ClientId { get; set; }
public string ClientName { get; set; }
public IList<AmountPaid> Amounts { get; set; }
}
public class AmountPaid
{
public decimal Amount { get; set; }
}
public class FirstAmountPaid : AmountPaid{ }
public class SecondAmountPaid : AmountPaid{ }
public class ThirdAmountPaid : AmountPaid{ }
public class FourthAmountPaid : AmountPaid{ }
Therefore giving a more meaningful code structure.
Thank you
i'm not sure why there are subclasses when the listposition already defines the order of the amounts
Map(x => x.Amounts)
.Columns.Add("First_AmountPaid", "Second_AmountPaid", "Third_AmountPaid", "Fourth_AmountPaid")
.CustomType<AmountPaidType>();
class AmountPaid : IUserType
{
public object Assemble(object cached, object owner)
{
return cached;
}
public object DeepCopy(object value)
{
return ((IList<AmountPaid>)x).Select(a => a.Clone()).ToList();
}
public object Disassemble(object value)
{
return value;
}
bool IUserType.Equals(object x, object y)
{
// assuming AmountPaid implements Equals
return ((IList<AmountPaid>)x).SequenceEquals((IList<AmountPaid>)y);
}
public int GetHashCode(object x)
{
return x.GetHashCode();
}
public bool IsMutable
{
get { return true; }
}
public void NullSafeSet(cmd, value, index)
{
var list = (IList<AmountPaid>)value;
NHibernateUtil.Double.NullSafeSet(cmd, list[0].Amount, index);
NHibernateUtil.Double.NullSafeSet(cmd, list[1].Amount, index + 1);
NHibernateUtil.Double.NullSafeSet(cmd, list[2].Amount, index + 2);
NHibernateUtil.Double.NullSafeSet(cmd, list[3].Amount, index + 3);
}
public object NullSafeGet(rs, names, owner)
{
var list = new List<AmountPaid>();
foreach (var name in names)
{
list.Add(new AmountPaid((double)NHibernateUtil.Double.Get(rs, name)));
}
return list;
}
public object Replace(object original, object target, object owner)
{
return original;
}
public Type ReturnedType
{
get { return typeof(IList<AmountPaid>); }
}
public SqlType[] SqlTypes
{
get { return new[] { SqlTypeFactory.Double, SqlTypeFactory.Double, SqlTypeFactory.Double, SqlTypeFactory.Double }; }
}
}