How to set the BAccount to updated so that sales force integration picks up that there was a update - salesforce

Good day
The SalesForce feature that can be enabled under licensing(Enable/Disable Features) integrates with SalesForce. It picked up that there was a change in the Business Account and sets the account to Modified locally(This can be seen in a new Tab in the Business Account).
I created a new field UsrCreditLimit in the BAccount. This is to move the Credit limit to the Business account so that the standard SalesForce integration can see the field.
The problem I have is when I update the field the SalesForce code to trigger the sync doesn't happen; The Field changes but the sync doesn't happen.
I have tested if I manually change the field the code does execute to trigger the sync. I have also tried opening a new Graph in the code to update the field without any luck.
Is there a way to set the BAaccount to Updated using the SalesForce dll/code.
namespace PX.Objects.AR
{
public class CustomerMaint_Extension : PXGraphExtension<CustomerMaint>
{
#region Event Handlers
public delegate void PersistDelegate();
[PXOverride]
public void Persist(PersistDelegate baseMethod)
{
Customer curCustomer = this.Base.CurrentCustomer.Select();
CR.BAccountExt curBAccountExt = curCustomer.GetExtension<CR.BAccountExt>();
curBAccountExt.UsrCreditLimit = curCustomer.CreditLimit.Value.ToString();
baseMethod();
}
}
}

Not sure if I understood your code correctly ...
Since a customer is a BAccount (it actually inherits from BAccount), why don't you also add your custom field to the Customer? and then it should be just a matter of updating this custom field. No need to call Save.PressButton again.

Related

Prevent one user from accessing a particular page when another user is already using it in .net core api and react js front end

We have a requirement to create a kind of user session. Our front end is react and backend is .net core 6 api and db is postgres.
When 1 user clicks on a delete button , he should not be allowed to delete that item when another user is already using that item and performing some actions.
Can you guys suggest me an approach or any kind of service that is available to achieve this. Please help
I would say dont make it too complicated. A simple approach could be to add the properties 'BeingEditedByUserId' and 'ExclusiveEditLockEnd' (datetime) to the entity and check these when performing any action on this entity. When an action is performed on the entity, the id is assigned and a timeslot (for example 10 minutes) would be assigned for this user. If any other user would try to perform an action, you block them. If the timeslot is expired anyone can edit again.
I have had to do something similar with Java (also backed by a postgres db)
There are some pitfalls to avoid with a custom lock implementation, like forgetting to unlock when finished, given that there is not guarantee that a client makes a 'goodbye, unlock the table' call when they finish editing a page, they could simply close the browser tab, or have a power outage... Here is what i decided to do:
Decide if the lock should be implemented in the API or DB?
Is this a distributed/scalable application? Does it run as just a single instance or multiple? If multiple, then you can not (as easily) implement an API lock (you could use something like a shared cache, but that might be more trouble than it is worth)
Is there a record in the DB that could be used as a lock, guaranteed to exist for each editable item in the DB? I would assume so, but if the app is backed by multiple DBs maybe not.
API locking is fairly easy, you just need to handle thread safety as most (if not all) REST/SOAP... implementations are heavily multithreaded.
If you implement at the DB consider looking into a 'Row Level Lock' which allows you to request a lock on a specific row in the DB, which you could use as a write lock.
If you want to implement in the API, consider something like this:
class LockManager
{
private static readonly object writeLock = new();
// the `object` is whatever you want to use as the ID of the resource being locked, probably a UUID/GUID but could be a String too
// the `holder` is an ID of the person/system that owns the lock
Dictionary<object, _lock> locks = new Dictionary<object, _lock>();
_lock acquireLock(object id, String holder)
{
_lock lok = new _lock();
lok.id = id;
lok.holder = holder;
lock (writeLock)
{
if (locks.ContainsKey(id))
{
if (locks[id].release > DateTime.Now)
{
locks.Remove(id);
}
else
{
throw new InvalidOperationException("Resource is already locked, lock held by: " + locks[id].holder);
}
}
lok.allocated = DateTime.Now;
lok.release = lok.allocated.AddMinutes(5);
}
return lok;
}
void releaseLock(object id)
{
lock (writeLock)
{
locks.Remove(id);
}
}
// called by .js code to renew the lock via ajax call if the user is determined to be active
void extendLock(object id)
{
if (locks.ContainsKey(id))
{
lock (writeLock)
{
locks[id].release = DateTime.Now.AddMinutes(5);
}
}
}
}
class _lock
{
public object id;
public String holder;
public DateTime allocated;
public DateTime release;
}
}
This is what i did because it does not depend on the DB or client. And was easy to implement. Also, it does not require configuring any lock timeouts or cleanup tasks to release locked items with expired locks on them, as that is taken care of in the locking step.

Entity Framework not creating Tables

I really have no luck with the EF every time. This time it looks like this:
First time i created a context i had an error like:
Invalid object name 'dbo.TableName1'
After this setting the Database Initializer to CreateDatabaseIfNotExists T it did the trick.
Next i created a different context, which was changed at some point of the development. So this time i keep getting this error:
The model backing the 'NewContext' context has changed since the database was created.
I found a solution to set the Database Initializer to null, but after this i keep getting the first error:
Invalid object name 'dbo.TableName2'
I also tried to set the the initializer to DropCreateDatabaseIfModelChanges and DropCreateDatabaseAlways, and these settings throw the exception:
Cannot drop database "DatbaseName" because it is currently in use
I think I already tried everything i found on the Web (there are many topics of this kind) but none helped me with it.
Dropping the Database didn't help, nor changing from Local File Database to SQL Server 2014 Exspress. The same exception is thrown. Any ideas?
Edit1:
Working context:
public class ProfilesContext : DbContext
{
public ProfilesContext() : base("DefaultConnection")
{
}
public DbSet<Profile> Profiles { get; set; }
public DbSet<PrevilegedContact> PrevilegedContacts { get; set; }
}
Failing context:
public class PlacesContext : DbContext
{
public PlacesContext()
: base("DefaultConnection")
{
}
public DbSet<Place> Places { get; set; }
public DbSet<Price> Prices { get; set; }
public DbSet<Photo> Photos { get; set; }
public DbSet<Comment> Comments { get; set; }
}
For what you are doing, it seems you have 2 options for your initializer. There is Migrations and there is DropCreateDatabaseIfModelChanges.
Migrations will give control over updating the database tables when your models change and allow you to preserve data. You can configure it to allow data loss or not. Very useful during development time if you already have test data in there.
DropCreateDatabaseIfModelChanges will simply drop the database each time you make model changes and recreate it with the new schemas.
You are getting the error message
Cannot drop database "DatbaseName" because it is currently in use
because you have more than likely browsed the table in your server explorer and have an open connection to the database. You can close the connection using the right click context menu in server explorer.
If you want a video overview on Migrations there is a free video by Scott Allen & Pluralsight. This is MVC4 but the Entity Framework section does cover Initalizers. If you want an updated one for MVC5 to include multiple Contexts etc, it does exist but you would need to take the Pluralsight free trial to get access to it.
I agree with James. Good point about checking Server Explorer. Right-click the database and choose Close Connection or at least check that there is a red X indicating the connection is closed. The link below is a great tutorial on the basics with Code First Migrations. The link is directly to the page within the tutorial that talks about making model changes and how to make EF happy again! http://www.asp.net/mvc/tutorials/mvc-5/introduction/adding-a-new-field. I prefer using Migrations. You would use the Package Manager Console and 1) Enable Migrations, 2) Add a migration, 3) Update the database. If in development, use LocalDb if possible, and use the Seed method in the Configuration class to prepopulate the database.

How to ensure unique column value inside code?

I am learning ASP.NET MVC, and confused as to how can I ensure unique values for columns (username & email) for a table.
Can anybody help me with a sample code or a link to the tutorial which shows & explains this?
EDIT:
I know that I can apply an unique key constraint on my table columns and achieve it. However, I want to know how can I achieve it via ASP.NET MVC code?
UPDATE:
I wish to do a check in my application such that no duplicated values are passed to DAL, i.e. achieve a check before inserting a new row.
Mliya, this is something you are controlling at the database level, not at the application level.
If you are designing a database with a users table in which you would like to constraint the username and email columns to be UNIQUE you should create a UNIQUE INDEX on such columns.
without knowing your backend database (mySQL, SQL Server, MS Access, Oracle...) it's not the case to show you pictures or tell much more, just create the table with the designer and add these unique constraints to those columns and by design you will be sure no duplicated values will ever be inserted for username and email.
I also suggest you to create an ID column which would be set as PK (primary key, which means it will be automatically set as NON NULL and UNIQUE).
From your ASP.NET MVC application you should of course make sure that no duplicated values are then passed to the DAL for username and email. You could do this in different ways, the easiest is probably to check before inserting a new row if any user already exists with that username and/or email and if so you can show a notification message telling the user to please select another pair of values.
In an ASP.NET MVC architecture, you should try to do most of your validation in the Model, but with low-level validation rules like these, it's sometimes impossible. What you should look to for answers then is Domain-driven Design (DDD) where Application Services can solve such low-level needs.
Application Services will have access to the database (either directly, or better yet; indirectly through repositories) and can perform low-level validation and throw ValidationException or something similar (with detailed information the Controller can act upon and respond to the user) when a prerequisite or business rule isn't met.
S#arp Architecture implementes all of this in a best-practice framework that you can use as a basis for your ASP.NET MVC applications. It is highly opinionated towards DDD principles and NHibernate, and it will sometimes force your hand on how you do stuff, which is kind of the point. The most important part about it is that it learns you how to deal with these kinds of problems.
To answer your question more concretely and in the spirit of DDD, this is how I would solve it:
public class UserController
{
private readonly IUserService userService;
public UserController(IUserService userService)
{
// The IUserService will be injected into the controller with
// an "Inversion of Control" container like NInject, Castle Windsor
// or StructureMap:
this.userService = userService;
}
public ActionResult Save(UserFormModel userFormModel)
{
if (userFormModel.IsValid)
{
try
{
// Mapping can be performed by AutoMapper or some similar library
UserDto userDto = Mapper.Map<UserDto>(userFormModel);
this.userService.Save(userDto);
}
catch (ValidationException ve)
{
ViewBag.Error = ve.Detail;
}
}
// Show validation errors or redirect to a "user saved" page.
}
}
public class UserService : IUserService
{
private readonly IUserRepository userRepository;
public UserService(IUserRepository userRepository)
{
// The IUserRepository will be injected into the service with
// an "Inversion of Control" container like NInject, Castle Windsor
// or StructureMap:
this.userRepository = userReposityr;
}
public UserDto Save(UserDto userDto)
{
using (this.userRepository.BeginTransaction())
{
if (!this.userRepository.IsUnique(userDto.UserName))
{
// The UserNameNotUniqueValidationException will inherit from ValidationException
// and build a Detail object that contains information that can be presented to
// a user.
throw new UserNameNotUniqueValidationException(userDto.UserName);
}
userDto = this.userRepository.Save(userDto);
this.userRepository.CommitTransaction();
return userDto;
}
}
}

Session Per Presenter NHibernate Desktop App - Not loading latest data from database

I'm writing a WPF NHibernate Desktop App using Session Per Presenter. I have a list view showing all the saved SalesOrders and an Edit Sales Order form when you double click on a Sales Order.
Each of these forms has a Session Object which lasts for the lifetime of the form. When a SalesOrder is saved it publishes an Event which tells the list view to re-load. The EditForm is definitely saving to the database and the ListView is definitely selecting from the database. However, the session that belongs to the ListViewPresenter is not updating its entities with those retrieved from the database. It just returns the same values as when the listSession was first loaded before anything was saved.
Below is some code which best replicates the scenario:-
[Test]
public void SessionPerPresenter()
{
//This session is the one that is used to load all salesorders from the database. It's lifetime is the lifetime of the form but as you double click on an entry in the list to edit it will stay alive longer than the session in the edit form
ISession listSession = NHibernateHelper.OpenSession();
SalesOrder order = new SalesOrder("P123435", "ACME");
order.AddLine(new SalesOrderLine("Beans", 15));
order.AddLine(new SalesOrderLine("Coke", 24));
order.AddLine(new SalesOrderLine("Pepsi", 3));
order.AddLine(new SalesOrderLine("Apples", 4));
//this session is the equivalent of the one in the Edit Form as soon as the entity is Saved
//the session is disposed
using (ISession session = NHibernateHelper.OpenSession())
{
session.SaveOrUpdate(order);
ID = order.SalesOrderID;
}
//retrieve all SalesOrders from the database and store them in a list
IList<SalesOrder> salesOrders = listSession.CreateCriteria<SalesOrder>().List<SalesOrder>();
foreach (SalesOrder so in salesOrders)
{
Console.WriteLine(so.ToString());
}
//edit the selected order and update its order code value and resave
using (ISession session = NHibernateHelper.OpenSession())
{
hydratedSalesOrder = session.Get<SalesOrder>(ID);
hydratedSalesOrder.OrderCode = "1234-5678";
session.SaveOrUpdate(hydratedSalesOrder);
session.Flush();
}
//re-retrieve the list of orders from the database. Using SQLServer Profiler / NHibernate profiler
//you can see the query being sent to the database so I don't believe it is in the cache. Indeed, if you run
//the query directly against the database the value 1234-5678 is returned. Can't work out why
//the listSession does not have the values read from the database in it but has the values from the
//original list retrieval.
salesOrders = listSession.CreateCriteria<SalesOrder>().List<SalesOrder>();
foreach (SalesOrder so in salesOrders)
{
Console.WriteLine(so.ToString());
}
listSession.Close()
}
Can someone help me with what is going on here? What am I doing wrong? Am I missing something vital? If it didn't query the database I would think it was something to do with the first level cache but that seems unlikely.
On way to ensure that your entities are not cached is to clear the session with ISession.Clear(). Also you can evict individual entities by calling ISession.Evict(object entity).
If you not sure of what is happening in your application, consider a profiling tool such as nhprof.
Quick note: using a session for the lifetime of a dialog can be handy in small applications with no concurrency problems, but you will get in trouble on the long run. A session should be opened late, and closed early.

Silveright - extending AuthenticationService to provide custom authentication

I am trying to add to the authentication system provided in the Silverlight 4 business template as my model does not completely fit that provided in the template. I have an existing web service that performs my authentication and provides roles and also permitted operations for each role. This is the model provided by AzMan/Authentication Manager.
However, rather than just get a single role, following authentication I provide the user with a list of available roles and allow the user to select one of these roles and then get a list of operations/actions for that selected role.
The problem that I have is that I can't work out how to add new methods to the authenticationservice to allow me to get the operations for the current user, and currently selected role in order to complete the login process e.g.
public SessionInfo GetOperations(string username, string selectedRole)
{
SessionInfo sessionInfo;
using (AzManServiceClient azClient = new AzManServiceClient("AnonymousAuthentication"))
{
sessionInfo = azClient.LoginUserByUsername("msldap://CN=LiveApps,CN=Program Data,DC=HLSUK,DC=local", "AIRS", selectedRole, null, username);
}
return sessionInfo;
}
The above method is not accessible from the LoginForm.xaml.cs using WebContextBase.Current.Authentication... Only methods such as Login are visible which is even more baffling because I can't see these methods in authenticationbase. I'm completely confused. How do I add new methods to the authentication service, or should I create a new domainservice, or should I access the azman service to get the operations directly from the silverlight client.
Have you tried to Override the methods in AuthenticationBase?
Then you can expand your authenticationservice with whatever logic you want.
<EnableClientAccess()>
Public Class AuthenticationRiaService
Inherits AuthenticationBase(Of UserAccount)
Protected Overrides Function ValidateUser(ByVal userName As String, ByVal password As String) As Boolean
End Function
End Class
Also set
WebContext.Current.Authentication To your authenticationservice as found in namespace System.ServiceModel.DomainServices.Client.ApplicationServices
Sorry for stupid VB code. :D

Resources