How to explicitly include mapped tables with PetaPoco - petapoco

I want to use PetaPoco on a table that has circa 600 tables, but I only want to map a handful of the tables.
Is there a way to explicitly state the tables I want mapping? The config in the t4 template (tables["tablename"].Ignore = true) doesn't really scale to this approach?

I ended up doing it like this:
Tables tables = LoadTables();
foreach(Table t in tables)
{
if(!t.Name.Contains("all_user_group"))
{
t.Ignore = true;
}
}

I have done something similar
var tablesToLoad= new string[] {
"TableOne",
"TableTwo",
"ViewOne",
"Etc" };
var tables = LoadTables();
foreach(var t in tables)
{
if(!tablesToLoad.Contains(t.Name))
{
t.Ignore = true;
}
}

To avoid having a T4 template filled with ignore assignments, I made a new database user that only had access to the tables I needed.
Then I connected the T4 template with the database user and PetaPoco only saw the tables I needed.

Related

How to make PetaPoco stop changing table names?

I'm using PetaPoco T4 Template (http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx), It always converting table names, for example it converts a table named "Media" to "Medium". Have you any idea how can I make it to stop doing that?
Thanks
In your .Database.tt file you can tweak the class names to your liking for each table:
tables["Media"].ClassName = "Media";
I don't know of a way to turn this off everywhere. I believe it is a remnant from the SubSonic inflector. In the SchemaReader classes you will see a call like this:
tbl.ClassName=Inflector.MakeSingular(tbl.CleanName);
You could try changing that to
tbl.ClassName=tbl.CleanName;
To prevent that, I put always this piece of code in the Database.tt file:
// Read schema
var tables = LoadTables();
foreach(Table t in tables)
{
if(!t.Name.ToLower().StartsWith("tablePrefix_"))
{
// Filter tables by prefix
t.Ignore = true;
}
else
{
// This do the trick discussed here
t.ClassName = t.CleanName;
}
}

given a list of objects using C# push them to ravendb without knowing which ones already exist

Given 1000 documents with a complex data structure. for e.g. a Car class that has three properties, Make and Model and one Id property.
What is the most efficient way in C# to push these documents to raven db (preferably in a batch) without having to query the raven collection individually to find which to update and which to insert. At the moment I have to going like so. Which is totally inefficient.
note : _session is a wrapper on the IDocumentSession where Commit calls SaveChanges and Add calls Store.
private void PublishSalesToRaven(IEnumerable<Sale> sales)
{
var page = 0;
const int total = 30;
do
{
var paged = sales.Skip(page*total).Take(total);
if (!paged.Any()) return;
foreach (var sale in paged)
{
var current = sale;
var existing = _session.Query<Sale>().FirstOrDefault(s => s.Id == current.Id);
if (existing != null)
existing = current;
else
_session.Add(current);
}
_session.Commit();
page++;
} while (true);
}
Your session code doesn't seem to track with the RavenDB api (we don't have Add or Commit).
Here is how you do this in RavenDB
private void PublishSalesToRaven(IEnumerable<Sale> sales)
{
sales.ForEach(session.Store);
session.SaveChanges();
}
Your code sample doesn't work at all. The main problem is that you cannot just switch out the references and expect RavenDB to recognize that:
if (existing != null)
existing = current;
Instead you have to update each property one-by-one:
existing.Model = current.Model;
existing.Make = current.Model;
This is the way you can facilitate change-tracking in RavenDB and many other frameworks (e.g. NHibernate). If you want to avoid writing this uinteresting piece of code I recommend to use AutoMapper:
existing = Mapper.Map<Sale>(current, existing);
Another problem with your code is that you use Session.Query where you should use Session.Load. Remember: If you query for a document by its id, you will always want to use Load!
The main difference is that one uses the local cache and the other not (the same applies to the equivalent NHibernate methods).
Ok, so now I can answer your question:
If I understand you correctly you want to save a bunch of Sale-instances to your database while they should either be added if they didn't exist or updated if they existed. Right?
One way is to correct your sample code with the hints above and let it work. However that will issue one unnecessary request (Session.Load(existingId)) for each iteration. You can easily avoid that if you setup an index that selects all the Ids of all documents inside your Sales-collection. Before you then loop through your items you can load all the existing Ids.
However, I would like to know what you actually want to do. What is your domain/use-case?
This is what works for me right now. Note: The InjectFrom method comes from Omu.ValueInjecter (nuget package)
private void PublishSalesToRaven(IEnumerable<Sale> sales)
{
var ids = sales.Select(i => i.Id);
var existingSales = _ravenSession.Load<Sale>(ids);
existingSales.ForEach(s => s.InjectFrom(sales.Single(i => i.Id == s.Id)));
var existingIds = existingSales.Select(i => i.Id);
var nonExistingSales = sales.Where(i => !existingIds.Any(x => x == i.Id));
nonExistingSales.ForEach(i => _ravenSession.Store(i));
_ravenSession.SaveChanges();
}

How to get list of changed (dirty) entities from Nhibernate session?

I need to write some business logic rigt before flush against all changed entities. One of the solution I've tried is IPreUpdateEventListener. But this event listener already have object denormalized to key-value. I need something before denormalization and even before flush.
So the questions is how to get list of changed (diry) entities.
My code to detect dirty entities
var dirtyObjects = new List<object>();
var sessionImpl = hsession.GetSessionImplementation();
foreach (NHibernate.Engine.EntityEntry entityEntry in sessionImpl.PersistenceContext.EntityEntries.Values)
{
var loadedState = entityEntry.LoadedState;
var o = sessionImpl.PersistenceContext.GetEntity(entityEntry.EntityKey);
var currentState = entityEntry.Persister.GetPropertyValues(o, sessionImpl.EntityMode);
if (entityEntry.Persister.FindDirty(currentState, loadedState, o, sessionImpl) != null)
{
dirtyObjects.Add(entityEntry);
}
}
You might look at the Flush event. But what are you trying to accomplish, exactly?
Well, best solution I've found is using PersistenceContext.
foreach (var entity in eventSource.PersistenceContext.EntityEntries.Keys)
{
// entity is entity to update...
}
Not sure if this is right solution, however.

Loading jqgrid from query with multiple joins

I am trying to load a sortable jqgrid 3.5 from a query with multiple joins in it and having much difficulty as I am a novice with both Linq and jqgrid. In order to allow for sorting I first was attempting to load it using dynamic SQL.
Since I am pulling columns from multiple tables I assume my return will be a class object which I will populate (or will it be a table). How can I return a IQueryable custom class object when using dynamic SQL with multiple .JOIN clauses. If this is impossible how do I return IQueryable data from a stored procedure call. It is easy to create dynamic SQL in the stored procedure - I am unsure how to load my grid with it however.
Sorry if this is all over the place but I can't seem to find a way. If you can recommend the most straight forward way to load my sortable grid from a query which has multiple joins in I am much appreciated.
My controller code:
public ActionResult GridData(string sidx, string sord, int page, int rows)
{
EquipTrak eqt = new EquipTrak();
var equipment = eqt.GetGridEquipment(sidx, sord);
var dataJson = new
{
total = 10000,
page = 1,
records = 10000,
rows = (from e in equipment
select new
{
equip_id = e.equip_id,
cell = new string[] {
e.equip_id,
e.equipType,
e.makeType,
String.Format("{0:MM/dd/yyyy}", e.serv_due_dt)
}
}).ToArray()
};
return Json(dataJson);
}
}
my class code (incomplete):
namespace ULS_Site.Models
{
public class EquipTrak
{
uls_dbDataContext ulsDB = new uls_dbDataContext();
public IQueryable<equipmentCls> GetGridEquipment(string sidx, string sord)
{
try
{
return
Not sure if this is the best or worst solution but I used SQL Server views to handle all the joining required. I could then use .Orderby and .Where against the view which was in my data context.

NHibernate: Creating a criteria which applies for all queries on a table

Using Castle ActiveRecord / NHibernate: Is there a way you can force an ICriterion on all queries on a table?
For example, a good amount of of my tables have a "UserId" column. I might want to ensure that I am always selecting rows for the logged in user. I can easily create an ICriterion object, but I am forced to supply it for different methods: FindAll(), FindFirst(), FindLast() etc.
Is there a way to force a WHERE clause on all queries to a Castle ActiveRecord?
I finally found a great solution (using filters). Since Castle AR does not have any native API for mapping to NHibernate filters, this part was pretty much undocumented. So here goes.
This example filter, will make sure you will never get news more than a year old, no matter what kind of query you use on the ActiveRecord. You can probably think of more practical applications for this.
First, create an ActiveRecord "News".
Use the following code before you initialize ActiveRecordStarter.
ActiveRecordStarter.MappingRegisteredInConfiguration += MappingRegisteredInConfiguration;
Castle.ActiveRecord.Framework.InterceptorFactory.Create = () => { return new EnableFiltersInterceptor(); };
Then, add the missing function and class:
void MappingRegisteredInConfiguration(Castle.ActiveRecord.Framework.ISessionFactoryHolder holder)
{
var cfg = holder.GetConfiguration(typeof (ActiveRecordBase));
var typeParameters = new Dictionary<string, IType>
{
{"AsOfDate", NHibernateUtil.DateTime}
};
cfg.AddFilterDefinition(new FilterDefinition("Latest", "", typeParameters));
var mappings = cfg.CreateMappings(Dialect.GetDialect(cfg.Properties));
var newsMapping = cfg.GetClassMapping(typeof (News));
newsMapping.AddFilter("Latest", ":AsOfDate <= Date");
}
public class EnableFiltersInterceptor : EmptyInterceptor
{
public override void SetSession(ISession session)
{
session.EnableFilter("Latest").SetParameter("AsOfDate", DateTime.Now.AddYears(-1));
}
}
And voila! Queries on News, e.g. FindAll(), DeleteAll(), FindOne(), Exists(), etc. will never touch entries more than a year old.
The closest thing would be using filters. See http://ayende.com/Blog/archive/2009/05/04/nhibernate-filters.aspx