asp.net mvc3 entity framework look up - asp.net

I have an application that has a status table see Database best practices - Status for an example
I want to be able to show a history of the status changes. There are 2 ways I can see for implementing it using mvc3 and the entity model like this - http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application
I can always just have a StatusID property on whatever object needs to link to the status table e.g.
Job
ID
Name
StatusID
Status
ID
Status
Or, I could have a StatusHistory table and make the StatusID property a function that return a Status object e.g.
Job
ID
Name
Status
ID
Status
StatusHistory
ID
JobID
StatusID
Date
and on the Job model class (Job.cs) have a function called Status which return 1 Status Object by querying the StatusHistory table for the latest status object that relates to the Job.
Has anyone done anything similar to this?

you may have
StatusHistory
ID
JobID
StatusID
Date
while Job contain current StatusID.
Job
ID
StatusID (latest)
this way you "cache" the Job's latest Status instead of searching..
StatusHistories.OrderDescending(s => s.Date).FirstOrDefault(); //unnecessary task
every time you need it.

What you are looking for is aTemporal Database. Pretty much, instead of keeping a ton of status codes you break the logic down into a pipeline of dates. For example, a date for job began, a date for job finished. Finished jobs should be migrated at some point to an archive to keep your database clean.

Related

DynamoDBAutoGeneratedTimestamp CREATE strategy is always updating?

I am trying to use the DynamoDBAutoGeneratedTimestamp annotation for generating timestamps for when my records are last updated and when they are created. The annotation currently has 2 strategies, ALWAYS and CREATE.
My initial understanding was that the ALWAYS strategy should update the timestamp every time the record is changed, and the CREATE strategy should set the timestamp only when the record is created. The ALWAYS strategy appears to be working just fine in updating the timestamp each time the record changes; however, the CREATE strategy appears to be behaving exactly the same as the ALWAYS strategy (meaning the timestamp updates each time the record changes).
It is now my understanding that the CREATE strategy doesn't do that, and instead tells the record to generate a timestamp if you're going to write it to the database and the value of the field in the record to be written is null.
This causes the field with the CREATE strategy to always be updated if the record itself is ever updated.
So, are there any easy solutions to this? I could set it myself, of course, but I was wondering if there is some sort of option or config that is not known to me that would address this issue?
Example code:
#DynamoDBTable(tableName = "Foo")
public class Foo {
#DynamoDBAutoGeneratedTimestamp(strategy = DynamoDBAutoGenerateStrategy.CREATE)
private Date createdAt;
#DynamoDBAutoGeneratedTimestamp(strategy = DynamoDBAutoGenerateStrategy.ALWAYS)
private Date updatedAt;
}

Asp.net Multi Tenancy implementation on existing solution

I have an asp.net MVC solution, Entity Framework code first, which has dozens of database tables all designed around a single company using the solution.
The requirement has come up to allow multiple companies to use the solution, so what we have done is add "CompanyID" as a column to all database tables and set a default value. There is a company table with the various company names and CompanyID's. On login the user selects the company they are logging in as which stores the CompanyID in the session.
At the moment every Entity Framework call now has to be updated to include the CompanyID, for example when selecting Employees I am doing:
List<Employee> employees = db.Employees.Where(x => x.CompanyID = Session.CompanyID).ToList();
As you can see it will be tedious to do this on thousands of calls to the db. Any update, save, and fetch has to change.
Surely I am doing it the long way and there is a way at runtime, globally to append all DB calls to include the CompanyID stored in the logged in users Session? Something that dynamically appends the CompanyID when fetching values or storing etc? Perhaps a package I can use to do this task at runtime?
In my opinion, there is no need to add CompanyID to EVERY table in the database. I would select just "root" tables/entities for that. For example, Employee or Department clearly sounds like a many-to-one relationship with a company - so adding CompanyID there sounds right. But, for example, EmployeeEquipment which is a many-to-one relationship with Employee does not have to have CompanyID column since it can be filtered by the joined Employee table.
Regarding your request to filter by CompanyID globally, I'm not aware of anything that can do that per request. There are global filters for Entity Framework, but I'm not sure how you can apply them per-request. Take a look on .HasQueryFilter() during model creation if you are using Entity Framework Core.

Marketo Leads - How to find the updated values of progressionStatus field

I need to get the Marketo Leads who have changes on "progressionStatus" field (inside membership) with the API.
I can get all the leads related to a Program (with Get Leads by ProgramID API) without issues, but my need is to get those Leads with changes on "progressionStatus" column.
I was thinking to use the CreatedAt / UpdatedAt fields of the Program, so then, get all the leads related to those programs. But I didn't get the accurate results that I want.
Also, I tried to use the GET Lead changes API and use "fields" parameter to "progressionstatus" but that field don't exist.
It is possible to resolve this?
Thanks in advance.
You can get the list of Leads with progression status change by querying against the Get Lead Activities endpoint.
The Get Lead Changes endpoint could sound as a good candidate, but that endpoint only returns changes on the lead fields. Progression status change is not stored on the lead directly, so at the end that won't work. On the other hand the Get Leads by ProgramId endpoint returns –amongst others– the actual value of progressionStatus (program status of the lead in the parent program) but not the “change” itself, so you cannot process the resultset based on that.
The good news is that the progression status change is an activity type and luckily we have the above mentioned Get Lead Activities endpoint (which is also mentioned as the Query in the API docs) available to query just that. This endpoint also allows for filtering by activityTypeIds to narrow down the resultset to a single activity type.
Basically you have to call the GET /rest/v1/activities.json enpoint and pass the values of activityTypeIds and nextPageToken as query parameters (next to the access token obviously). So, first you need to get the internal Id of the activity type called “Change Status in Progression”. You can do that by querying the GET /rest/v1/activities/types.json endpoint and look for a record with that name. (I don't know if this Id changes from instance to instance, but in ours it is the #104). Also, to obtain a nextPageToken you have to make a call to GET /rest/v1/activities/pagingtoken.json as well, where you have to specify the earliest datetime to retrieve activities from. See more about Paging Tokens.
Once you have all of these bits at hand, you can make your request like that:
GET https://<INSTANCE_ID>.mktorest.com/rest/v1/activities.json?activityTypeIds=<TYPE_ID>&nextPageToken=<NEXTPAGE_TOKEN>&access_token=<ACCESS_TOKEN>
The result it gives is an array with items like below, which is easy to process further.
{
"id":712630,
"marketoGUID":"712630",
"leadId":824864,
"activityDate":"2017-12-01T08:51:13Z",
"activityTypeId":104,
"primaryAttributeValueId":1104,
"primaryAttributeValue":"PROGRAM_NAME",
"attributes":[
{"name":"Acquired By","value":true},
{"name":"New Status ID","value":33},
{"name":"Old Status ID","value":32},
{"name":"Reason","value":"Filled out form"},
{"name":"Success","value":false},
{"name":"New Status","value":"Filled-out Form"},
{"name":"Old Status","value":"Not in Program"}
]
}
Knowing the leadIds in question, you can make yet another request to fetch the actual lead records.

How to keep old and new version of record until a supervisor approves the changes?

I am currently working on a ASP.NET MVC 3 project in which I have to keep record of field changes with certain attributes. Example:
public class MyModel
{
public String PropertyOne { get; set; }
// Need to keep track of these properties
[RequiresSupervisorKey]
public String PropertyTwo { get; set; }
}
As soon as one of the fields is changed, it requires a supervisor to approve of these field changes.
Until the changes have been approved the record will be in a pending state, and I somehow need to keep the old record and the new record until such time!
What is the best practices regarding storing these records? Should I have 2 records in the table in the database or should i have a audit table that can store this data until it has been approved.
Thank you.
I'd save them in one table too. Use a combined key for identifying a unique row. Row ID with autoincretment id. and datetime as the second part of the combined key. When a 3rd row can store the state. This allows you versioning as well. If you select the field for display you select by id order by datetime desc where state is approved limit 1. Hope this helps ;-)
This is my .02 from other projects but I would add a version or state column to the table and keep n number of records in the table. I don't know if its possible in your system for the record to be changed by two different users with different changes, but in situations like this that is usually the case. An audit table is an acceptable solution but in general I prefer to keep things in one table.
I would keep both records in the table (old and new) with an extra field for status (such as active, pending, delete, disapproved) (or what ever statuses you think you need).
Then I would create a view that shows only the active records (used for most purposes) and one that shows only the pending records (uses for the supervisor approval page).
I would create a trigger on the table to ensure only one record was active at a time. So if a supervisor changed a record from pending to active, it would take the old record and change it to the delete status. If a supervisor disapproved a change, it would go to the disapproved status.
To keep the table nimble (you indicate no need to permanently store the old statuses), I would have a job that runs at night to delete all records in the delete or disapproved status.

When assigning values to EntityRef ID fields in Linq to Sql, can EntityRef still delay load?

I've got an ASP.NET MVC app that uses Linq to Sql for data access.
Say I have two objects: An Order object that has a foreign key to a Customer object by CustomerID. So, in my Order class, you would see two properties: an int CustomerID field, and an EntityRef member accessible by a Customer property.
When the edits or submits an Order, my MVC app will update the CustomerID field directly of the Order class, instead of updating the Customer property. This saves us from having to fetch a customer record, and I can use the default model binding code to fill the property automatically as long as the submitted form request has a customerID entry.
This works ok, however, later on in some other part of the code--say a business rules portion, some logic will access the Customer property of the Order object. For example:
if (order.Customer.HasPreviousOrders) then ...
Even though the CustomerID field is set, the Customer field is null, so this business rule throws an exception.
I know Linq 2 Sql uses EntityRefs to do delayed loading. My question is: is there a way to trigger the delayed loading on an object's EntityRef if the ID field has been modified?
We have a dynamic rules engine, so I don't have control of what foreign key objects are going to be needed. I'd rather not have to go through all my controllers to set the EntityRef<> values directly.
Thanks for the help.
Ok, no takers. It looks like what I'm trying to do is just not doable--or maybe not a good idea.
I went ahead and implemented code so I am setting the association object property instead of the ID property so the business rules can be processed.

Resources