Linq to SQL TransactionScope - linq-to-sql

I have the following scenario:
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted },EnterpriseServicesInteropOption.Automatic))
{
using (DataContext db = new DataContext())
{
db.Connection.Open();
db.Transaction = db.Connection.BeginTransaction();
try
{
bool outcome = InvokeInTransaction<string, object>(inputDict, out outputDict);
db.Transaction.Commit();
}
catch (Exception ex)
{
response.Outcome = BusinessEntityResponse.SystemError;
db.Transaction.Rollback();
}
}
}
Inside the InvokeInTransaction call are a number of calls made to a LTS repository to perform various data changes. The problem is that inside the repository there is another
using (var db = new DataContext())
Inside which is the persistence code. Inspecting the context in the repository shows Transaction = null and I suspect that the "inner" context has no knowledge of the Ambient transaction. Can this be done? I understand that EF manages this under the covers, and the constraint is that the repository code cannot be changed. Any help?

We use LinqToSql and TransactionScope for multiple database transactions. You should really control your connection/context/transaction lifecycles if you're going to attempt it.
We control DataContext instances by the rule: If you new one up, you do that with a using statement.
We control connection lifecycles by the rule: If you open it, you must close it (but generally let the DataContext instances manage that).
We control transaction lifecycles by the rule: let DataContext manage what goes on in SubmitChanges and let TransactionScope manage what goes on within its using block.
Here's a code sample:
using (OuterDataContext outerDataContext = GetOuterDataContext())
{
using (InnerDataContext innerDataContext = GetInnerDataContext())
{
try
{
OuterRepository outerRepository = new OuterRepository();
// may read records into memory for updating/deleting.
outerRepository.WorkWithOuterRecords(outerRecords, outerDataContext);
InnerRepository innerRepository = new InnerRepository();
// may read records into memory for updating/deleting.
innerRepository.WorkWithInnerRecords(innerRecords, innerDataContext);
using (TransactionScope scope = new TransactionScope())
{
//starts a local tranaction in outerDB, held open by scope
outerDataContext.SubmitChanges();
//promotes the transaction to distributed, still held open by scope
innerDataContext.SubmitChanges();
// and done
scope.Complete();
}
}
catch (Exception ex)
{
LoggerClient.Log(ex);
response.Message = "It didn't save anything.";
}
}
}

Related

Enforce Microsoft.Build to reload the project

I'm trying to iteratively (part of automation):
Create backup of the projects in solution (physical files on the filesystem)
Using Microsoft.Build programmatically load and change projects inside of the solution (refernces, includes, some other properties)
Build it with console call of msbuild
Restore projects (physically overriding patched versions from backups)
This approach works well for first iteration, but for second it appears that it does not load restored projects and trying to work with values that I patched on the first iteration. It looks like projects are cached: inside of the csproj files I see correct values, but on the code I see previously patched values.
My best guess is that Microsoft.Build is caching solution/projects in the context of the current process.
Here is code that is responsible to load project and call method to update project information:
private static void ForEachProject(string slnPath, Func<ProjectRootElement> patchProject)
{
SolutionFile slnFile = SolutionFile.Parse(slnPath);
var filtredProjects = slnFile
.ProjectsInOrder
.Where(prj => prj.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat);
foreach (ProjectInSolution projectInfo in filtredProjects)
{
try
{
ProjectRootElement project = ProjectRootElement.Open(projectInfo.AbsolutePath);
patchProject(project);
project.Save();
}
catch (InvalidProjectFileException ex)
{
Console.WriteLine("Failed to patch project '{0}' with error: {1}", projectInfo.AbsolutePath, ex);
}
}
}
There is Reload method for the ProjectRootElement that migh be called before iteraction with content of the project.
It will enforce Microsoft.Build to read latest information from the file.
Code that is working for me:
private static void ForEachProject(string slnPath, Func<ProjectRootElement> patchProject)
{
SolutionFile slnFile = SolutionFile.Parse(slnPath);
var filtredProjects = slnFile
.ProjectsInOrder
.Where(prj => prj.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat);
foreach (ProjectInSolution projectInfo in filtredProjects)
{
try
{
ProjectRootElement project = ProjectRootElement.Open(projectInfo.AbsolutePath);
project.Reload(false); // Ignore cached state, read actual from the file
patchProject(project);
project.Save();
}
catch (InvalidProjectFileException ex)
{
Console.WriteLine("Failed to patch project '{0}' with error: {1}", projectInfo.AbsolutePath, ex);
}
}
}
Note: It better to use custom properties inside of the project and provide it for each msbuild call instead of physical project patching. Please consider it as better solution and use it if possible.

How to preview upcoming invoices using the Zuora SOAP API?

From the Zuora user interface I can preview a subscription using a convenient "Preview" button. I'd like to perform the same action using the Zuora SOAP API so that I can preview what the upcoming invoices and write some tests.
So far, my theory is to create an empty Amendment with PreviewOptions.enablePreviewMode=true to get the results of the previewed invoice.
Relevant SOAP docs:
Amend docs
InvoiceData docs
This has partially worked, but it has returned one InvoiceData object, but two would be expected.
public List<InvoiceData> getInvoicePreview(String subscriptionId){
ID id = new ID();
id.setID(subscriptionId);
PreviewOptions previewOptions = new PreviewOptions();
previewOptions.setEnablePreviewMode(true);
previewOptions.setPreviewThroughTermEnd(true);
Calendar forever = new DateTime().plusDays(1000).toCalendar(Locale.getDefault());
// A null amendment
Amendment amendment = new Amendment();
amendment.setName("Draft amendment for preview");
amendment.setStatus("Draft");
amendment.setContractEffectiveDate(forever);
amendment.setSubscriptionId(id);
amendment.setType("TermsAndConditions");
AmendOptions amendOptions = new AmendOptions();
AmendRequest amendRequest = new AmendRequest();
amendRequest.setAmendments(new Amendment[]{amendment});
amendRequest.setAmendOptions(amendOptions);
amendRequest.setPreviewOptions(previewOptions);
Amend amend = new Amend();
amend.setRequests(new AmendRequest[]{amendRequest});
AmendResponse amendResults;
try {
ZuoraCredentials creds = credentialProvider.get();
ZuoraServiceStub stub = new ZuoraServiceStub(creds.zuoraApiEndpoint);
Login login = new Login();
login.setUsername(creds.zuoraApiUser);
login.setPassword(creds.zuoraApiPassword);
LoginResponse loginResponse = stub.login(login);
String session = loginResponse.getResult().getSession();
SessionHeader sessionHeader = new SessionHeader();
sessionHeader.setSession(session);
amendResults = stub.amend(amend, sessionHeader);
} catch (RemoteException e) {
throw new RuntimeException("Error executing Zuora API.", e);
} catch (UnexpectedErrorFault e) {
throw new RuntimeException("Error executing Zuora API.", e);
} catch (LoginFault e) {
throw new RuntimeException("Error executing Zuora API.", e);
}
AmendResult[] amendResult = amendResults.getResults();
printOut(amendResult);
return new ArrayList<InvoiceData>(Arrays.asList(amendResult[0].getInvoiceDatas()));
}
Here's what the data looks like from the Zuora UI
I have been trying to achieve something similar myself for a subscribe() call and ended up raising a ticket with Zuora. They said that it was not supported but you could achieve the same thing by aggregating the InvoiceItem records.
What I have done is manually group them together based on the start of the service period (ServiceStartDate) and sum the totals (e.g. ChargeAmount, TaxAmount). It appears to work out correctly and you can get the total due at the start of each period.
I suspect this will work for amendments in the same way because an InvoiceData record is returned in the same was as for subscribe().
Update
We do now use this for amendments and it does work well in the same way as for subscribe calls.
One problem we have found is that you cannot preview beyond the end of a termed subscription, but we can set the term type to EVERGREEN if needed when previewing (even if the subscription is to be TERMED when created).

Mallet Api - Get consistent results

I am new to LDA and mallet. I have the following query
I tried running Mallet-LDA with the command line and by setting the --random-seed to a fixed value, I was able to get consistent results for multiple runs of the algorithm
However, I did try with the Mallet-Java-API and everytime I run the program I get different output.
I did google around and found out that random-seed needs to be fixed and I have it fixed in my java code. I still am getting different results.
Could anyone let me know what other parameters do I need to consider for consistent results (when run multiple times)
I might want to add that train-topics when ran multiple times(command line) yields same result. However, when I rerun import-dir and then run train-topics, the results do not match with previous one. (Probably as expected).
I am ok with running import-dir just once and then experiment with different number of topics and iterations by running train-topics.
Similarly, what needs to be changed/ kept constant if I want to replicate the same when I use Java-Api.
I was able to solve this.
I will respond in detail here:
There are two ways in which Mallet could be run.
a. Command mode
b. Using Java API
To get consistent results for different runs, we need to fix the 'random seed' and in the command line we have an option of setting it. We have no surprises there.
However, while using APIs, though we have an option of setting 'random seed', we need to know that it needs to be done at proper point, else it does not work. (see code)
I have pasted the code here which would create a model(read InstanceList) file from the data
and then we could use the same model file and set the random seed and see to it that we get consistent(read same) results every time we run.
Creating and saving model for later use.
Note: Follow this link to know the format of input file.
http://mallet.cs.umass.edu/ap.txt
public void getModelReady(String inputFile) throws IOException {
if(inputFile != null && (! inputFile.isEmpty())) {
List<Pipe> pipeList = new ArrayList<Pipe>();
pipeList.add(new Target2Label());
pipeList.add(new Input2CharSequence("UTF-8"));
pipeList.add(new CharSequence2TokenSequence());
pipeList.add(new TokenSequenceLowercase());
pipeList.add(new TokenSequenceRemoveStopwords());
pipeList.add(new TokenSequence2FeatureSequence());
Reader fileReader = new InputStreamReader(new FileInputStream(new File(inputFile)), "UTF-8");
CsvIterator ci = new CsvIterator (fileReader, Pattern.compile("^(\\S*)[\\s,]*(\\S*)[\\s,]*(.*)$"),
3, 2, 1); // data, label, name fields
InstanceList instances = new InstanceList(new SerialPipes(pipeList));
instances.addThruPipe(ci);
ObjectOutputStream oos;
oos = new ObjectOutputStream(new FileOutputStream("Resources\\Input\\Model\\Model.vectors"));
oos.writeObject(instances);
oos.close();
}
}
Once model file is saved, this uses the above saved file to generate topics
public void applyLDA(ParallelTopicModel model) throws IOException {
InstanceList training = InstanceList.load (new File("Resources\\Input\\Model\\Model.vectors"));
logger.debug("InstanceList Data loaded.");
if (training.size() > 0 &&
training.get(0) != null) {
Object data = training.get(0).getData();
if (! (data instanceof FeatureSequence)) {
logger.error("Topic modeling currently only supports feature sequences.");
System.exit(1);
}
}
// IT HAS TO BE SET HERE, BEFORE CALLING ADDINSTANCE METHOD.
model.setRandomSeed(5);
model.addInstances(training);
model.estimate();
model.printTopWords(new File("Resources\\Output\\OutputFile\\topic_keys_java.txt"), 25,
false);
model.printDocumentTopics(new File ("Resources\\Output\\OutputFile\\document_topicssplit_java.txt"));
}

Windows phone 8 notification hub unregister

Can someone show me or tell some example how to unregister from notification hub in windows phone 8. I tried on this way but it doesn't work.
public void registerForNotifications(string[] tags)
{
var channel = HttpNotificationChannel.Find("xxx");
if (channel == null)
{
channel = new HttpNotificationChannel("xxx");
channel.Open();
channel.BindToShellToast();
}
string[] tagsToSubscribeTo = tags;
channel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(async (o, args) =>
{
var hub = new NotificationHub("xxx", "xxx");
await hub.RegisterNativeAsync(args.ChannelUri.ToString(), tagsToSubscribeTo);
});
}
public async void unregisterFromNotifications()
{
var channel = HttpNotificationChannel.Find("xxx");
var hub = new NotificationHub("xxx", "xxx");
await hub.UnregisterAllAsync(channel.ChannelUri.ToString());
}
You didn't say what "it didn't work" means. Did you get an error message? Did it report success but actually fail? In your questions, it really helps more if you share those things. But I'll take a stab at this anyway.
I suspect that you might be using the DefaultListenSharedAccessSignature endpoint from your Windows Phone 8 app.
According to http://msdn.microsoft.com/en-us/library/dn495373.aspx, the Listen access level grants permission to:
Create/Update registration.
Read registration.
Read all registrations for a handle.
Delete registration.
Reading that last one, I wonder if the UnregisterAllAsync method might require a higher access level to delete all registrations, rather than just one.
But rather than use the DefaultFullSharedAccessSignature endpoint, I would rather just try the UnregisterAsync method instead of UnregisterAllAsync.
Disclaimer: I have not tried this out. It may not help at all.

When modifying linq-to-sql commandtext, should the connection be closed?

I'm modifying the commandtext of linq-to-sql to force it to use nolock, like this...
if (db.Connection.State == System.Data.ConnectionState.Closed)
db.Connection.Open();
var cmd = db.GetCommand(db.Customers.Where(p => p.ID == 1));
cmd.CommandText = cmd.CommandText.Replace("[Customers] AS [t0]", "[Customers] AS [t0] WITH (NOLOCK)");
var results = db.Translate(cmd.ExecuteReader());
It's an MVC application, so the datacontext is in the base controller, and may have been used before this code, and more importantly, after. Should I be closing the connection in this routine? Or not at all? Or only if I opened it here?
Update:
I'm now using the more general function (in the DataContext class) to modify the commandtext, and closing the connection if it was opened here. And the open has been moved down to the ExecuteReader. So far it has been working and reducing the sporadic deadlock issues. The results do not have to be right-up-to-the-second.
public List<T> GetWithNolock<T>(IQueryable<T> query)
{
// to skip nolock, just...
// return query.ToList();
List<T> results = null;
bool opened = false;
try
{
if (Connection.State == System.Data.ConnectionState.Closed)
{
Connection.Open();
opened = true;
}
using (var cmd = GetCommand(query))
{
cmd.CommandText = Regex.Replace(cmd.CommandText, #"((from|inner join) \[dbo.*as \[t\d+\])", "$1 with (nolock)", RegexOptions.IgnoreCase);
results = Translate<T>(cmd.ExecuteReader()).ToList();
}
}
finally
{
if (opened && Connection.State == System.Data.ConnectionState.Open)
{
Connection.Close();
}
}
return results;
}
I have found in the past that using a Transaction in the recommended way causes the site to run out of connections overnight. As far as I know, that's a bug in linq-to-sql. There may be ways around it, but I'm trying to keep my main code straightforward. I now "just" have to do this...
var users = GetWithNolock<User>(
Users
.Where(u => my query
);
If you Open it, you should Close it. Other LinqToSql operations match this pattern.
In my code, I unconditionally open the connection and close the connection in a finally. If someone passes me an open connection, that's their fault and I happen to close it for them.
You could delay opening the connection until just before ExecuteReader.