How to correctly handle DTO conversion in Micronaut Reactive - project-reactor

Lets say we are working with Micronaut Reactive (Project Reactor) and we would like to create a user account. SignUp DTO is represented by the following Kotlin class:
#Introspected
data class SignUpDto(
#field:Schema(example = "admin")
#field:NotBlank #field:Max(value = 255) var username: String? = null,
// rest is omitted for brevity
)
In order to create and persist an account entity in the database, first, we have to convert the SignUpDTO to the account entity represented by the kotlin class below:
#Entity(name = "Accounts")
#Where("#.active = true")
open class AccountEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "accounts_sequence_generator")
#SequenceGenerator(name = "accounts_sequence_generator", sequenceName = "sequence_accounts")
#Column(name = "id", nullable = false, unique = true)
open var id: Long? = null
#Column(name = "username", nullable = false, unique = true, updatable = false, length = 255)
open var username: String? = null
#Column(name = "active", nullable = false)
open var active: Boolean? = true
#ManyToMany(fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST, CascadeType.MERGE])
#JoinTable(name = "accounts_roles",
joinColumns = [JoinColumn(name = "accounts", referencedColumnName = "id")],
inverseJoinColumns = [JoinColumn(name = "roles", referencedColumnName = "id")])
open var roles: MutableSet<RoleEntity> = mutableSetOf()
// rest is omitted for brevity
}
As you can see, AccountEntity has a many-to-many relationship on a RoleEntity. For completeness, RoleEntity is shown below:
#Entity(name = "Roles")
open class RoleEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "id", nullable = false, unique = true)
open var id: Long? = null
#Column(name = "role", nullable = false, unique = true)
#Enumerated(EnumType.STRING)
open var role: Role? = null
#Column(name = "description", nullable = false, length = 500)
open var description: String? = null
// rest is omitted for brevity
}
Application defines a RoleRepository as follows:
#Repository
interface RoleRepository : ReactorCrudRepository<RoleEntity, Long> {
fun findByRole(role: Role): Mono<RoleEntity>
}
We are interested in mapping a SignUpDTO request to an account entity and persisting that entity in a reactive way. Function that does the converting is given below:
fun convertSignUpToAccountEntity(#Valid signUpDto: SignUpDto): AccountEntity {
return AccountEntity().apply {
this.username = signUpDto.username
this.active = true
this.roles.add(**add a user role here**)
}
}
Given that the RoleRepository is available to this function, how would one fetch the Role.User entity and add it to the list of account roles in a reactive way, since calling block just indefinitely blocks the calling thread? Is there a way to handle this in a reactive way?

You can have something like this:
return Flux.fromIterable(Arrays.asList("role1", "role2"))
.flatMap(role -> roleRepository.findByRole(role))
.collectList()
.map(roles -> convertSignUpToAccountEntity(signUpDto, roles))
.flatMap(accountEntityRepository::save);

Related

Xamarin Android, get contact mobile number by using CursorLoader with selection and selection args

I'm trying to get contact details of a contact that the user picks from the contacts list in Android using Intent as the following code:
Intent Intent = new Intent(Intent.ActionPick, ContactsContract.Contacts.ContentUri);
Intent.SetType(ContactsContract.Contacts.ContentType);
StartActivityForResult(Intent, 3);
Now on the Intent results I run the following code to get specific contact information:
public override void OnActivityResult(int requestCode, int resultCode, Intent data)
{
if (requestCode == 3 && resultCode == -1 && data != null) //result code -1 means OK 0 Means cancelled Result.Ok
{
var ContactData = data.Data;
string ID = "";
string name = "";
string address = "";
byte[] picture = new byte[0];
List<string> numbers = new List<string>();
List<string> emails = new List<string>();
string mobile = "";
string email = "";
string selectionString = "id = ?";
string[] columnsNames = new string[] {
ContactsContract.Contacts.InterfaceConsts.Id,
ContactsContract.Contacts.InterfaceConsts.DisplayName,
ContactsContract.Contacts.InterfaceConsts.PhotoUri
};
var loader = new CursorLoader(Statics.mainActivity, ContactData, null, null, null, null);
var cursor = (ICursor)loader.LoadInBackground();
if (cursor.MoveToFirst())
{
ID = cursor.GetString(cursor.GetColumnIndex(columnsNames[0]));
name = cursor.GetString(cursor.GetColumnIndex(columnsNames[1]));
picture = cursor.GetBlob(cursor.GetColumnIndex(columnsNames[2]));
}
//Store Contact ID
string[] selectionStringArgs = new string[] { ID };
//Phone Numbers
string[] columnsNames2 = new string[] {
ContactsContract.CommonDataKinds.Phone.Number
};
var loader2 = new CursorLoader(Statics.mainActivity, ContactsContract.CommonDataKinds.Phone.ContentUri, columnsNames2, selectionString, selectionStringArgs, null);
var cursor2 = (ICursor)loader2.LoadInBackground();
while (cursor2.MoveToNext())
{
numbers.Add(cursor2.GetString(cursor2.GetColumnIndex(columnsNames2[0])));
}
//Email Address
string[] columnsNames3 = new string[] {
ContactsContract.CommonDataKinds.Email.Address
};
var loader3 = new CursorLoader(Statics.mainActivity, ContactsContract.CommonDataKinds.Email.ContentUri, columnsNames3, selectionString, selectionStringArgs, null);
var cursor3 = (ICursor)loader3.LoadInBackground();
while (cursor3.MoveToNext())
{
emails.Add(cursor3.GetString(cursor3.GetColumnIndex(columnsNames3[0])));
}
int TempRecepitntID = 0;
EmployeesViewModel tempRecipent = new EmployeesViewModel();
TempRecepitntID = Statics.mainActivity.currentViewModel.SelectedChat.ReceiverEmployee;
foreach (EmployeesViewModel evm in Statics.mainActivity.currentViewModel.Employees)
{
if (evm.ID == TempRecepitntID)
tempRecipent = evm;
}
new Android.Support.V7.App.AlertDialog.Builder(Statics.mainActivity)
.SetPositiveButton("Yes", (sender1, args) =>
{
Statics.mainActivity.currentViewModel.AddMessage(picture, tempRecipent, Statics.mainActivity.currentViewModel.SelectedChat.ID, "contact", 0, "", name, numbers[0], mobile, email, address);
})
.SetNegativeButton("No", (sender1, args) =>
{
// cancel
})
.SetMessage("Are you shure you want to send?")
.SetTitle("System Message")
.Show();
}
}
The problem is I want to retrieve only the information of the contact that the user selected but what I get is all other contacts data is retrieved so I tried to use the selection and selectionargs parameters of CursorLoader by setting string selectionString = "id = ?"; and selectionArgs to string[] selectionStringArgs = new string[] { ID }; the ID value is retrieved from the following code :
if (cursor.MoveToFirst())
{
ID = cursor.GetString(cursor.GetColumnIndex(columnsNames[0]));
name = cursor.GetString(cursor.GetColumnIndex(columnsNames[1]));
picture = cursor.GetBlob(cursor.GetColumnIndex(columnsNames[2]));
}
//Store Contact ID
string[] selectionStringArgs = new string[] { ID };
//Phone Numbers
string[] columnsNames2 = new string[] {
ContactsContract.CommonDataKinds.Phone.Number
};
But now it returns 0 results, I couldn't find anything on the internet that applies to Xamarin android, Please help.
Thanks,
Finally I found the solution, I used the following string in the selection parameter of the cursorloader method:
string selectionString = ContactsContract.CommonDataKinds.Phone.InterfaceConsts.ContactId + "=" + ID;
and now only the selected contact numbers are retrieved.
I hope this will help someone else.
In additional information of #TMSL, I add the code afer this bloque
if (cursor.MoveToFirst())
{
ID = cursor.GetString(cursor.GetColumnIndex(columnsNames[0]));
name = cursor.GetString(cursor.GetColumnIndex(columnsNames[1]));
picture = cursor.GetBlob(cursor.GetColumnIndex(columnsNames[2]));
}
Here
selectionString = ContactsContract.CommonDataKinds.Phone.InterfaceConsts.ContactId + "=" + ID;
Then I changed the parameters used in the definition of variable Loader2, converting selectionStringArgs in null.
var loader2 = new CursorLoader(this.Activity, ContactsContract.CommonDataKinds.Phone.ContentUri, columnsNames2, selectionString, null,null);
var cursor2 = (ICursor)loader2.LoadInBackground();
I found this documentation from xamarin guides
Uri – The fully qualified name of the ContentProvider.
Projection – Specification of which columns to select for the cursor.
Selection – Similar to a SQL WHERE clause.
SelectionArgs – Parameters to be substituted in the Selection.
SortOrder – Columns to sort by.
So, the variable selectionStringArgs used in the code from #TMSAL cannot use a value like "contact_id = 2700", because the parameter of CursorLoader SelectionArgs is not a filter but not "Parameters to be substituted in the Selection"
I hope this will help someone else too.

How to call aspnet_UsersInRoles_IsUserInRole Stored Procedure with Dapper ORM

I need to call aspnet_UsersInRoles_IsUserInRole from Aspnet Membership.Im making dapper call like this:
public int CheckIfUserIsInRole(IsUserInRole userInRole)
{
using (var connection = new SqlConnection(ConfigurationSettings.GetConnectionString()))
{
DynamicParameters param = new DynamicParameters();
param.Add("#UserName", userInRole.UserName);
param.Add("#ApplicationName", userInRole.ApplicationName);
param.Add("#RoleName", userInRole.RoleName);
return connection.Query("aspnet_UsersInRoles_IsUserInRole", param, commandType: CommandType.StoredProcedure).FirstOrDefault();
}
}
And in controller i add:
public int IsUserInRole(IsUserInRole isUserInRole)
{
var model = _userRepository.CheckIfUserIsInRole(new IsUserInRole()
{
UserName = "testuser",
RoleName = "user",
ApplicationName = "USERMANAGEMENT"
});
return model;
}
The user exist and have the correct role but every time returns 0.
Here is the Stored Procedure from AspNet Membership:
ALTER PROCEDURE [dbo].[aspnet_UsersInRoles_IsUserInRole]
#ApplicationName nvarchar(256),
#UserName nvarchar(256),
#RoleName nvarchar(256)
AS
BEGIN
DECLARE #ApplicationId uniqueidentifier
SELECT #ApplicationId = NULL
SELECT #ApplicationId = ApplicationId FROM aspnet_Applications WHERE LOWER(#ApplicationName) = LoweredApplicationName
IF (#ApplicationId IS NULL)
RETURN(2)
DECLARE #UserId uniqueidentifier
SELECT #UserId = NULL
DECLARE #RoleId uniqueidentifier
SELECT #RoleId = NULL
SELECT #UserId = UserId
FROM dbo.aspnet_Users
WHERE LoweredUserName = LOWER(#UserName) AND ApplicationId = #ApplicationId
IF (#UserId IS NULL)
RETURN(2)
SELECT #RoleId = RoleId
FROM dbo.aspnet_Roles
WHERE LoweredRoleName = LOWER(#RoleName) AND ApplicationId = #ApplicationId
IF (#RoleId IS NULL)
RETURN(3)
IF (EXISTS( SELECT * FROM dbo.aspnet_UsersInRoles WHERE UserId = #UserId AND RoleId = #RoleId))
RETURN(1)
ELSE
RETURN(0)
END
Where I'm mistaking?
Any advice how to fix it ?
I need this Stored Procedure to check if the user is in that role so i can use it for [AuthorizeRoles("RoleTest")]
That stored procedure doesn't return any records; it uses the return value instead. This needs to be handled as a parameter:
public int CheckIfUserIsInRole(IsUserInRole userInRole)
{
using (var connection = new SqlConnection(ConfigurationSettings.GetConnectionString()))
{
DynamicParameters param = new DynamicParameters();
param.Add("#UserName", userInRole.UserName);
param.Add("#ApplicationName", userInRole.ApplicationName);
param.Add("#RoleName", userInRole.RoleName);
param.Add("#ReturnValue", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);
connection.Execute("aspnet_UsersInRoles_IsUserInRole", param, commandType: CommandType.StoredProcedure);
return param.Get<int>("#ReturnValue");
}
}
https://github.com/StackExchange/dapper-dot-net#stored-procedures
(Also posted to your copy of this question on CodeProject.)

Inconsistency in grails command object validation

I have following command object with constraints :
#Validateable
class RefundCommand{
private static final Logger log = Logger.getLogger(RefundCommand.class)
Double amount
String order_id
MerchantAccount merchant
OrderReference order
String unique_request_id
public void getDerivedValues() {
this.order = OrderReference.findByOrderIdAndMerchantId(order_id, merchant.merchantId)
}
static constraints = {
amount nullable: false, validator: {amount, cmd->
if(cmd.amount <= 0) {
log.info("Amount must be greater than 0. Given value: ${cmd.amount}")
return ['invalid.amount']
}
}
}
}
Initiating an object in following way inside a controller:
def refund = {RefundCommand cmd->
def String orderId = params.orderId
def String merchantId = params.merchant.merchantId
def Double amount = params.amount.toDouble()
OrderReference orderReference = OrderReference.findByOrderIdAndMerchantId(orderId, merchantId)
MerchantAccount merchantAccount = MerchantAccount.findByMerchantId(merchantId)
cmd.order_id = orderId
cmd.merchant = merchantAccount
cmd.order = orderReference
cmd.amount = amount
cmd.unique_request_id = "rf_" + util.generateUniqueReference()
cmd.clearErrors()
cmd.validate()
log.info(cmd.dump())
if(cmd.hasErrors()) {
.....
return
}
proceedForRefund()
}
When I deploy initially validations are not working, validate() always return true and hasError() return null.
As we are using nginx, if I make any change in RefundCommand file then after auto-compile validation start working.
What could be the reason for that?
we are using grails-2.2.2 with nginx server.

passing model and parameter with RedirectToAction

I want to send a string and a model (object) to another action.
var hSM = new HotelSearchModel();
hSM.CityID = CityID;
hSM.StartAt = StartAt;
hSM.EndAt = EndAt;
hSM.AdultCount = AdultCount;
hSM.ChildCount = ChildCount;
return RedirectToAction("Search", new { culture = culture, hotelSearchModel = hSM });
When I use the new keyword it sends null object, although I set the objects hSm property.
This is my Search action :
public ActionResult Search(string culture, HotelSearchModel hotelSearchModel)
{
// ...
}
You can't send data with a RedirectAction.
That's because you're doing a 301 redirection and that goes back to the client.
What you need to is save it in TempData:
var hSM = new HotelSearchModel();
hSM.CityID = CityID;
hSM.StartAt = StartAt;
hSM.EndAt = EndAt;
hSM.AdultCount = AdultCount;
hSM.ChildCount=ChildCount;
TempData["myObj"] = new { culture = culture,hotelSearchModel = hSM };
return RedirectToAction("Search");
After that you can retrieve again from the TempData:
public ActionResult Search(string culture, HotelSearchModel hotelSearchModel)
{
var obj = TempData["myObj"];
hotelSearchModel = obj.hotelSearchModel;
culture = obj.culture;
}

Call a method in Linq to EF

In order to create a ViewModel, I tried to call a method GetName() to find the FirstName and LastName for UserID and then add it to the model. But the error tells "Linq to Entities does not recognize the method".
How do I accomplish this in another way?
My code:
public IQueryable<SheetList> GetSheetData()
{
var query = from a in GetSheets()
select new SheetList
{
SheetId = a.ListAllSafetySheets.Id,
SheetTitle = a.ListAllSafetySheets.SafetySheetTitle,
ProductionManagerId = a.ListAllSafetySheets.ProductionManager,
ProductionManagerName = this.GetName(a.ListAllSafetySheets.ProductionManager),
ConstructionManagerId = a.ListAllSafetySheets.ConstructionManager,
Created = a.ListAllSafetySheets.Created,
CreatedBy = a.ListAllSafetySheets.CreatedBy,
UserProfile_UserId = a.ListAllUserProfiles.UserId,
Project_Id = a.ListAllProjects.Id,
ProjectLeaderId = a.ListAllProjects.ProjectLeader,
ConstructionLocation_Id = a.ListAllConstructionLocations.Id,
};
return query;
}
public IQueryable<DataCollection> GetSheets()
{
var query = from vSafety in _db.Sheets
join vUserProfile in _db.UserProfiles
on vSafety.Id
equals vUserProfile.UserId
join vProject in _db.Projects
on vSafety.Id
equals vProject.Id
join vConstructionLocation in _db.ConstructionLocations
on vSafety.Id
equals vConstructionLocation.Id
orderby vSafety.Created descending
select new SafetyAndProjectAndUserAndLocationCollection
{
ListAllSafetySheets = vSafety,
ListAllUserProfiles = vUserProfile,
ListAllProjects = vProject,
ListAllConstructionLocations = vConstructionLocation
};
return query;
}
public string GetName(int? id)
{
string returnValue;
if (id == null)
{
var userModel = _db.UserProfiles.Single(x => x.UserId == id);
string FirstName = userModel.FirstName;
string LastName = userModel.LastName;
returnValue = FirstName + ", " + LastName;
}
else
{
returnValue = "";
}
return returnValue;
}
You'll need to call the method after you build the model. You can try something like this:
public IQueryable<SheetList> GetSheetData()
{
var query = from a in GetSheets()
select new SheetList
{
SheetId = a.ListAllSafetySheets.Id,
SheetTitle = a.ListAllSafetySheets.SafetySheetTitle,
ProductionManagerId = a.ListAllSafetySheets.ProductionManager,
ProductionManagerName = a.ListAllSafetySheets.ProductionManager,
ConstructionManagerId = a.ListAllSafetySheets.ConstructionManager,
Created = a.ListAllSafetySheets.Created,
CreatedBy = a.ListAllSafetySheets.CreatedBy,
UserProfile_UserId = a.ListAllUserProfiles.UserId,
Project_Id = a.ListAllProjects.Id,
ProjectLeaderId = a.ListAllProjects.ProjectLeader,
ConstructionLocation_Id = a.ListAllConstructionLocations.Id,
};
var queryWithNames = query.ToList().ForEach(s => s.ProductionManagerName = this.GetName(s.ProductionManagerName));
return queryWithNames;
}
Since you're having trouble using .ForEach(), you can do this with a regular foreach loop:
foreach(var s in query)
{
s.ProductionManagerName = this.GetName(s.ProductionManagerName);
}
The downside to this is the call to .ToList will enumerate the queryable, executing the query against the database, so if you need to do further filters later outside this method, you may be downloading additional data that you don't need, causing additional overhead.

Resources