Why do I need to name the properties in my index with underscore? - indexing

Given that I have the following structure (unnecessary details stripped out)
public class Product {
public Guid Id { get; set; }
public string Name { get; set; }
public Manufacturer Manufacturer { get; set; }
}
public class Manufacturer {
public Guid Id { get; set; }
public string Name { get; set; }
}
If I have a lot of these kind of products stored in raven and I want to index them by manufacturer id (or maybe some other things as well) I'd make an index such as this (of course in real life this index also contains some other information as well...)
public class ProductManufacturerIndex : AbstractIndexCreationTask<Product> {
public ProductManufacturerIndex() {
Map = products => from product in products
select new {
Manufacturer_Id = product.Manufacturer.Id,
};
}
}
My question here is, why do I need to name my field Manufacturer_Id? If I do not name it Manufacturer_Id I get exceptions when attempting to query my index since the manufacturer id column is not indexed.
Basically, why can't I do this? (Which would be my first guess)
public class ProductManufacturerIndex : AbstractIndexCreationTask<Product> {
public ProductManufacturerIndex() {
Map = products => from product in products
select new {
product.Manufacturer.Id,
};
}
}

There is a naming convention that RavenDB uses. If you aren't naming your fields properly, it doesn't know how to map things.
In this case, the second index you use has a property of Id, but RavenDB has no way of knowing that you mapped the Manufacturer's id, and not the root id.
That is why we have this convention. You can change it if you really want to, but it is generally not recommended.

Related

Why EF core tries to add navigational property into DB and not only the Id of foreign model?

I was wondering why EF tries to add also foreign models.
Example:
public class Category
{
public int Id { get; set; }
public string Name{ get; set; }
}
public class Content
{
public int Id { get; set; }
public string Name{ get; set; }
public Category Category{ get; set; }
}
After creating "Content" using migrations, I have a table that includes the id of category. That's create. So I have three columns: Id, name and the categoryId. Seems EF "knows" that this should be just the primary key of Category, that needs to get stored.
Than I tried to add something with EF.
var cat = new Category {Id = 2, Name = "awesomeCat"})
var addContent = new Content({Name = "test", Category = cat})
Now I want to add a Content by using _context.Add(addContent). I was expecting a single insert into db that uses the name "test" and the categoryId 2. Id will be generated by DB.
But instead EF also tries to add a new Category into the category table.
So I took a deeper look and seems EF "does" not know it already exists and was not maintaining any transactions about the category model.
I gave it another try and used no new category, instead I was loading it before:
var cat = _context.findById("2");
and assigned this one instead. Now EF should know that this one already exists and does not have to add it in category table.
Could it be, that my model is just wrong.
Do I need to use it more like:
public class Content
{
public int Id { get; set; }
public string Name{ get; set; }
public int? CategoryId{ get; set; }
[ForeignKey("CategoryId")]
public Category Category{ get; set; }
}
Won't I get two category references then?
You need to tell EF Core it's a primary key and to generate the key
public class Category
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
}
public class Content
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public Category Category { get; set; }
}
Then you don't need to mark [ForeignKey("CategoryId")], EF Core will turn the object reference into an ID in the database
If I misunderstood your question, ask again :)
EF Core has internal tracking of entities. When you simply new up a category, it's not being tracked. When you add the content, EF will track any related entities as well, which would include your category, which will by default be tracked as "Added". You have a few choices.
Don't "new up" an existing category, but rather, retrieve it from the database. If EF pulls it from the database, then it will be tracked, and will not be added again.
You can explicitly track the category instance you newed up and set it's state to "Unchanged".
_context.Attach(category);
_context.Entry(category).State = EntityState.Unchanged;
_context.Add(content);
The best method is to not deal with the reference property at all, and use an explicit foreign key property. Add a property to your content class:
public int CategoryId { get; set; }
Then, you can simply set this id, instead of the Category prop:
var addContent = new Content { Name = "test", CategoryId = 2 };
EF will backfill the reference property after save.

One-to-Many relationship with ORMLite

The only examples I can find addressing this sort of scenario are pretty old, and I'm wondering what the best way is to do this with the latest version of ORMLite...
Say I have two tables (simplified):
public class Patient
{
[Alias("PatientId")]
[Autoincrement]
public int Id { get; set; }
public string Name { get; set; }
}
public class Insurance
{
[Alias("InsuranceId")]
[Autoincrement]
public int Id { get; set; }
[ForeignKey(typeof("Patient"))]
public int PatientId { get; set; }
public string Policy { get; set; }
public string Level { get; set; }
}
Patients can have multiple Insurance policies at different "levels" (primary, secondary, etc). I understand the concept of blobbing the insurance information as a Dictionary type object and adding it directly to the [Patient] POCO like this:
public class Patient
{
public Patient() {
this.Insurances = new Dictionary<string, Insurance>(); // "string" would be the Level, could be set as an Enum...
}
[Alias("PatientId")]
[Autoincrement]
public int Id { get; set; }
public string Name { get; set; }
public Dictionary<string, Insurance> Insurances { get; set; }
}
public class Insurance
{
public string Policy { get; set; }
}
...but I need the insurance information to exist in the database as a separate table for use in reporting later.
I know I can join those tables in ORMLite, or create a joined View/Stored Proc in SQL to return the data, but it will obviously return multiple rows for the same Patient.
SELECT Pat.Name, Ins.Policy, Ins.Level
FROM Patient AS Pat JOIN
Insurance AS Ins ON Pat.PatientId = Ins.PatientId
(Result)
"Johnny","ABC123","Primary"
"Johnny","987CBA","Secondary"
How can I map that into a single JSON response object?
I'd like to be able to map a GET request to "/patients/1234" to return a JSON object like:
[{
"PatientId":"1234",
"Name":"Johnny",
"Insurances":[
{"Policy":"ABC123","Level":"Primary"},
{"Policy":"987CBA","Level":"Secondary"}
]
}]
I don't have a lot of hope in this being do-able in a single query. Can it be done in two (one on the Patient table, and a second on the Insurance table)? How would the results of each query be added to the same response object in this nested fashion?
Thanks a ton for any help on this!
Update - 4/29/14
Here's where I'm at...In the "Patient" POCO, I have added the following:
public class Patient
{
[Alias("PatientId")]
[Autoincrement]
public int Id { get; set; }
public string Name { get; set; }
[Ignore]
public List<Insurance> Insurances { get; set; } // ADDED
}
Then, when I want to return a patient with multiple Insurances, I do two queries:
var patientResult = dbConn.Select<Patient>("PatientId = " + request.PatientId);
List<Insurance> insurances = new List<Insurance>();
var insuranceResults = dbConn.Select<Insurance>("PatientId = " + patientResult[0].PatientId);
foreach (patientInsurance pi in insuranceResults)
{
insurances.Add(pi);
}
patientResult[0].Insurances = insurances;
patientResult[0].Message = "Success";
return patientResult;
This works! I get nice JSON with nested items for Insurances while maintaining separate related tables in the db.
What I don't like is that this object cannot be passed back and forth to the database. That is, I can't use the same nested object to automatically insert/update both the Patient and InsurancePolicy tables at the same time. If I remove the "[Ignore]" decorator, I get a field in the Patient table called "Insurances" of type varchar(max). No good, right?
I guess I'm going to need to write some additional code for my PUT/POST methods to extract the "Insurances" node from the JSON, iterate over it, and use each Insurance object to update the database? I'm just hoping I'm not re-inventing the wheel here or doing a ton more work than is necessary.
Comments would still be appreciated! Is Mythz on? :-) Thanks...
An alternate more succinct example:
public void Put(CreatePatient request)
{
var patient = new Patient
{
Name = request.Name,
Insurances = request.Insurances.Map(x =>
new Insurance { Policy = i.Policy, Level = i.Level })
};
db.Save<Patient>(patient, references:true);
}
References are here to save the day!
public class Patient
{
[Alias("PatientId")]
[Autoincrement]
public int Id { get; set; }
public string Name { get; set; }
[Reference]
public List<Insurance> Insurances { get; set; }
}
public class Insurance
{
[Alias("InsuranceId")]
[Autoincrement]
public int Id { get; set; }
[ForeignKey(typeof("Patient"))]
public int PatientId { get; set; }
public string Policy { get; set; }
public string Level { get; set; }
}
I can then take a JSON request with a nested "Insurance" array like this:
{
"Name":"Johnny",
"Insurances":[
{"Policy":"ABC123","Level":"Primary"},
{"Policy":"987CBA","Level":"Secondary"}
]
}
...to create a new record and save it like this:
public bool Put(CreatePatient request)
{
List<Insurance> insurances = new List<Insurance>();
foreach (Insurance i in request.Insurances)
{
insurances.Add(new Insurance
{
Policy = i.Policy,
Level = i.Level
});
}
var patient = new Patient
{
Name = request.Name,
Insurances = insurances
};
db.Save<Patient>(patient, references:true);
return true;
}
Bingo! I get the new Patient record, plus 2 new records in the Insurance table with correct foreign key references back to the PatientId that was just created. This is amazing!
First you should define a foreign collection in Patient class. (with get and set methods)
#ForeignCollectionField
private Collection<Insurance> insurances;
When you query for a patient, you can get its insurances by calling getInsurances method.
To convert all into a single json object with arrays inside you can use a json processor. I use Jackson (https://github.com/FasterXML/jackson) and it works very well. Below will give you json object as a string.
new ObjectMapper().writeValueAsString(patientObject);
To correctly map foreign fields you should define jackson references. In your patient class add a managed reference.
#ForeignCollectionField
#JsonManagedReference("InsurancePatient")
private Collection<Insurance> insurances;
In your insurance class add a back reference.
#JsonBackReference("InsurancePatient")
private Patient patient;
Update:
You can use Jackson to generate objects from json string then iterate and update/create database rows.
objectMapper.readValue(jsonString, Patient.class);

Easier way to store list of id's in a parent document using RavenDB

If I have a parent document that can have multiple children such as a Store can have multiple Products is there any easier way to store a list of Product.Id in the Store document?
Currently I am just storing the Product objects first and then looping through them to get the Product.Id for the Store.ProductIds property.
Store
class Store
{
public string Id { get; set; }
public string Name { get; set; }
public IList<string> ProductIds { get; set; }
[JsonIgnore]
public IList<Product> Products { get; set; }
}
Product
class Product
{
public string Id { get; set; }
public string Name { get; set; }
}
Current Working Save Method
var store = new Store()
{
Name = "Walmart",
Products = new List<Product>
{
new Product {Name = "Ball"},
new Product {Name = "Bat"}
}
};
using (var session = DocumentStore.OpenSession())
{
foreach (var product in store.Products)
{
session.Store(product);
}
session.SaveChanges();
var list = new List<string>();
foreach (var product in store.Products)
{
list.Add(product.Id);
}
store.ProductIds = list;
session.Store(store);
session.SaveChanges();
}
To answer your specific question - there are two things you can simplify with the code:
You can eliminate the first session.SaveChanges(); The product ids will be created when you call .Store() on the product.
You can gather the product ids with some linq to collapse it to one line:
store.ProductIds = store.Products.Select(x=> x.Id).ToList();
You still have the same general approach though - it's just simplifying the code a bit.
This approach will work, but do realize that you are just putting the Products in the Store for convenience. [JsonIgnore] is ok here, but it only helps with serialization - not deserialization. In other words, when loading a store, only the ProductIds list will be populated. You would have to load them separately (possibly using .Include())
Personally, I would take the Products list out of the Store object altogether. Other relational products like Entity Framework and NHibernate use virtual members and proxy classes for this purpose, but it has little meaning in RavenDB. A consumer of your class won't know that the property is ignored, so they might misunderstand its usage. When I see the Products property, my expectation is that each Product is fully embedded in the document - in which case you wouldn't need the separate ProductIds list. Having them both with one ignored just causes confusion.
Another argument against your proposed design would be that it implicitly makes every product in every store unique. This is because you are creating the products with the store, and then adding each one separately. If it is indeed the case that all products are unique (not just "ball", but "this specific ball"), then you could just embed the product without the [JsonIgnore] or the ProductIds list, and there would be no need for Product to exist as a separate document. In the more likely scenario that products are not unique (multiple stores can sell bats and balls), then you have two options:
class Store
{
public string Id { get; set; }
public string Name { get; set; }
public IList<string> ProductIds { get; set; }
}
class Store
{
public string Id { get; set; }
public string Name { get; set; }
public IList<Product> Products { get; set; }
}
Product would still be in its own document with either case - the second scenario would be used as a denormalized reference so you can get at the product name without loading the product. This is acceptable, but if product names can change, then you have lots of patching to do.
Sorry if there's no clean "do it this way" answer. Raven has lots of options, sometimes one way or another works better depending on all the different ways you might use it. Me personally - I would just keep the list of ProductIds. You can always index the related document to pull in the product name for querying purposes.

NHibernate (Fluent) Lazy Loading Not Working

I am attempting to use NHibernate to generate a model for a very odd database. The tables themselves have primary keys for show only, all the actual relationships are on unique columns. For example, a product table with a product id primary key and a unique product name column. Another table, demand, has a product name column and that defines the relationship. I know this situation isn't ideal but it's out of my control.
At any rate, I was able to use Fluent NHibrenate to map product to demand, but I cannot seem to get the entity to lazy-load.
public class Demand
{
public virtual DemandId { get; set; }
public virtual Product { get; set; }
}
public class DemandMap : ClassMap<Demand>
{
public DemandMap()
{
this.Table("Demand");
this.LazyLoad();
this.Id(x => x.DemandId);
this.References(x => x.Product).PropertyRef(x => x.ProductName).LazyLoad();
}
}
Does anyone have any insight into why lazy loading is not working? I know it is not because I can see the product being fetched along with the demand in the SQL profiler.
My idea (Maybe you can try use "HasMany" there is example but you can read something about this):
First class
public class Demand
{
public virtual int DemandId { get; set; }
public virtual int Product { get; set; }
public virtual IEnumerable<NewClass> Name {get; set;}
}
this.HasMany(x=> x.Product).Column("Product_id").not.nullable;
Second class
public class NewClass
{
public virtual Demand Product_id {get; set;}
}
this.References(x => x.Product).Column("product_id).not.nullable

How to use look up values with NHibernate?

How do you handle look up values with NHibernate? For example, I have an Order entity and it has a BillingAddress property that is a value object named Address, it's simple if the Address object just contains State and Country properties as strings. But what if I want a Country contains a list of its states the Order form can populate appropriate state dropdown list for each selected country.
Can I still create Country and State as value objects? Or they must be entities? And if they are entities, can Address be a value object?
Below is a sample code of my example:
public class Order
{
public virtual int OrderId { get; set; }
public virtual Address BillingAddress { get; set; }
}
public class Address
{
public virtual State State { get; set; }
public virtual Country Country { get; set; }
}
public class Country
{
public virtual string Name { get; set; }
public virtual ICollection<State> States { get; set; }
}
public class State
{
public virtual string Name { get; set; }
public virtual Country Country { get; set; }
}
If you want to store the lookup data in the database, then they need to be entities. Otherwise, it is up to you. If you do, I suggest marking them as immutable and putting them in a read only 2nd-layer cache.
If you store them as values, and they have multiple fields like Abbrevation, Name, Coordinates, etc. then you can save the id as a value in the data store, and have the lookup data hard-coded as a plain C# class. You'll just retrieve the id value from NHibernate, and then your calling code will have to run the lookup methods on the class. Not as elegant, but simplifies from the NHibernate/database perspective.
Either method is acceptable--it more depends on how you plan on using them: who is maintaining and using the code at each level, where you want the caching and/or lookup code, if you control the calling code or not, etc.