I have a domain called Test that has been running look-up SQL queries to select from another database.
I want to get away from this implementation and goto multiple datasource support of Grails 2.0. However, the table name in the other database is a called Panel.
Is it possible to map the domain to the alternative database and also map which table it selects from?
// Datasource.groovy
development {
dataSource {
dbCreate = 'create-drop' // one of 'create', 'create-drop','update'
url = "jdbc:sqlserver://machine\\SQLEXPRESS;databaseName=primarydb"
username = "user"
password = "password"
}
dataSource_otherdb {
url = "jdbc:sqlserver://remoteserver:1433;databaseName=otherdb"
}
}
// Test.groovy
class Test {
String name
int key
String abbreviation
boolean active = true
static mapping = {
sort name: "asc"
datasource("otherdb")
}
}
There is a "table"configuration in mapping closure for that.
// Test.groovy
class Test {
String name
int key
String abbreviation
boolean active = true
static mapping = {
table 'Panel' //customize table name
sort name: "asc"
datasource("otherdb")
}
}
Related
I am trying to update individual records in sqlite database. I know how to Insert and delete records. I'd like to Update an individual record in a similar way to how I am deleting an individual record below. This uses a linq statement to get the record by Asset ID. I'd then like to pass my data to this to update.
I've also included how I insert a new record for reference. Does anybody have an example that they could share?
Delete an existing record
using (SQLiteConnection localconn = new SQLiteConnection(App.FilePath))
{
localconn.CreateTable<Road_Inspections>();
localconn.Table<Road_Inspections>().Where(x => x.Unique_ID == unique_ID).Delete();
}
Insert new record
Road_Inspections lri = new Road_Inspections()
{
ID = id,
Road_ID = Road_ID.Text.ToString(),
Asset_ID = Asset_ID.Text.ToString(),
Defect_Type = txtDefectType.Text.ToString(),
Response = txtResponse.Text.ToString(),
Inspection_Date = DateTime.Now,
};
using (SQLiteConnection conn = new SQLiteConnection(App.FilePath))
{
conn.CreateTable<Road_Inspections>();
int rowsAdded = conn.Insert(lri);
await DisplayAlert("Success", "Inspeciton Saved to Device", "OK");
}
You need a primary Key or Id in your object Announcement to identify your unique object in your database, for example:
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
Since you want to update you have to get the original entry from the database first.
And then you can edit and update it. So, you don't need to delete it before you insert a new one.
In xamarin form you can use nuget sqlite-net-pcl to achieve this.
Please refer to the following code:
public Task<int> SaveItemAsync(TodoItem item)
{
if (item.ID != 0)
{
return Database.UpdateAsync(item);
}
else
{
return Database.InsertAsync(item);
}
}
For more details,you can check: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/data-cloud/data/databases .
And there is a sample included in above document, you can check it here:https://learn.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/todo/
I'm using spring-ldap-core-2.3.1.RELEASE.jar over JDK 1.8 & Tomcat 8.0 to access AD information through LdapTemplate. The attributes such as title,department & company are not being returned by the ldapTemplate.search(..,.,..) method.
I'm using the following lines of code to search :-
LdapQuery ldapQuery = LdapQueryBuilder.query()
.where("objectclass").is("user")
.and("objectcategory").is("person")
.and("cn").like(strWildcardText+"*");
ldapTemplate.search(ldapQuery, new ADUserAttributesMapper());
Following is the ADUserAttributesMapper class :-
public class ADUserAttributesMapper implements AttributesMapper<ADUserBean> {
#Override
public ADUserBean mapFromAttributes(Attributes attributes) throws NamingException {
if(attributes==null) {
return null;
}
adUserBean.setName((attributes.get("name")!=null) ? attributes.get("name").get().toString() : null);
adUserBean.setCommonName((attributes.get("cn")!=null) ? attributes.get("cn").get().toString() : null);
adUserBean.setDisplayName((attributes.get("displayname")!=null) ? attributes.get("displayname").get().toString() : null);
adUserBean.setGivenName((attributes.get("givenname")!=null) ? attributes.get("givenname").get().toString() : null); // for FIRST NAME
adUserBean.setMiddleName((attributes.get("initials")!=null) ? attributes.get("initials").get().toString() : null); // for MIDDLE NAME / INITIALS
adUserBean.setLastName((attributes.get("sn")!=null) ? attributes.get("sn").get().toString() : null); // for LAST NAME
adUserBean.setDepartment((attributes.get("department")!=null) ? attributes.get("department").get().toString() : null);
adUserBean.setUserPrincipalName((attributes.get("userprincipalname")!=null) ? attributes.get("userprincipalname").get().toString() : null); // Logon Name
adUserBean.setsAMAccountName((attributes.get("samaccountname")!=null) ? attributes.get("samaccountname").get().toString() : null); // Logon Name (pre-Windows 2000)
adUserBean.setDistinguishedName((attributes.get("distinguishedname")!=null) ? attributes.get("distinguishedname").get().toString() : null);
adUserBean.setMailID((attributes.get("mail")!=null) ? attributes.get("mail").get().toString() : null);
adUserBean.setTitle((attributes.get("title")!=null) ? attributes.get("title").get().toString() : null); // Job Title
adUserBean.setTelephoneNumber((attributes.get("telephonenumber")!=null) ? attributes.get("telephonenumber").get().toString() : null);
adUserBean.setObjectCategory((attributes.get("objectcategory")!=null) ? attributes.get("objectcategory").get().toString() : null);
return adUserBean;
}
}
The title,department & company attributes belong to the Organization tab of the AD user properties as shown in the below image :-
Also, from the General tab the initials(initials) attribute is not being picked up/listed by Spring-LDAP's ldapTemplate. The LdapQueryBuilder.query() object has access to attributes(...) method that takes a string array of attribute names that are to be fetched. But even after mentioning them there explicitly, values for attributes such as initials, title, department & company are not returned.
The LDAP Browser plugin within the Eclipse IDE lists the title,department & company properties under the Organization tab without a problem.
Even the com4j API returns the title, department & company attributes.
Is there any configuration that is limiting the attribute(s) listing or is it a limitation with Spring-LDAP API itself? Are these attributes not part of BasicAttributes? How to fetch these attributes through Spring-LDAP?
UPDATE (01-Aug-2017):
The plain Java JNDI approach/code does NOT return department,company,title attributes (even with these attributes being explicitly mentioned in attributes string array), but surprisingly it does return the initials attribute value.
UPDATE (02-Aug-2017):
Similar to #Pierre's suggestion (below) tried the following code using SearchControls object :-
String strFilter= "(&(objectclass=top)(cn=cgma*))";
String[] attrs = new String[] {"cn","givenName","sn","initials","title","department","company"};
long maxResults = 10; // for example
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
searchControls.setReturningAttributes(attrs);
searchControls.setCountLimit(maxResults);
List<String> aLstOfADUsers = ldapTemplate.search("",strFilter,searchControls,new AttributesMapper<String>()
{
public String mapFromAttributes(Attributes attrs) throws NamingException {
try
{
System.out.println(attrs.toString());
return attrs.get("cn").get().toString();
}
catch(Exception ex) {
ex.printStackTrace();
return null;
}
}
});
return aLstOfADUsers;
Even this does not return the initials, title, company & department attribute values.
The person attributes might be internal attributes which you wouldn't get back by default. You can specify explicitly which attributes you want returned BUT not in the search method you're using (the one where you pass in an LdapQuery object). If you take a look at the org.springframework.ldap.core.LdapTemplate class, it doesn't seem like you can pass in the SearchControls object to the method signature you're using. So, to be able to specify attributes to fetch, replace this:
LdapQuery ldapQuery = LdapQueryBuilder.query()
.where("objectclass").is("user")
.and("objectcategory").is("person")
.and("cn").like(strWildcardText+"*");
ldapTemplate.search(ldapQuery, new ADUserAttributesMapper());
With this:
LikeFilter filter = new LikeFilter("cn", strWildcardText+"*");
// list of attributes to retrieve
String[] attrs = new String[] {"title","department","company"};
long maxResults = 10; // for example
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
searchControls.setReturningAttributes(attrs);
searchControls.setCountLimit(numResults);
ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), searchControls, new ADUserAttributesMapper());
The above should work. You could also try something like this (I haven't tried that yet):
ldapTemplate.search( "dc=yourorg,dc=com",
"(&(cn=" +strWildcardText + "*)(&(objectClass=person)(objectcategory=person)))",
SearchControls.SUBTREE_SCOPE,
new String[]{ "title","department","company" },
new ADUserAttributesMapper() );
Finally, to get ALL attributes back, ask to retrieve ALL attributes in the code above (my above example only asked for 3 attributes, this would return ALL of them):
String[] attrs = new String[]{"*","+"};
This is based on your AttributesMapper. I don't know what ADUserAttributesMapper is, so you'd have to provide that implementation.
Here's the javadoc for this interface. http://docs.spring.io/spring-ldap/docs/current/apidocs/org/springframework/ldap/core/AttributesMapper.html
Change ldap port from 3268 to 389
I'm trying to extend the UserType with a custom AccountPart.
I don't want user account id to be a content part id, i want AccountId field to be an independent auto increment 5 digit number (like 10300, 10301) or at least auto generated Guid.
I've tried number of times to achieve it, but still didn't.
Here is on of my tries. The result is 00000000-0000-0000-0000-000000000000 for the 1st user, and for the second i got an exception. The Guid didn't generated =(.
AccountPart:
public Guid AccountId
{
get { return Record.AccountId; }
set { Record.AccountId = Guid.NewGuid(); }
}
public decimal RealMoney
{
get { return Record.RealMoney; }
set { Record.RealMoney = value; }
}
public decimal VirtualMoney
{
get { return Record.VirtualMoney; }
set { Record.VirtualMoney = value; }
}
public decimal BonusPoints
{
get { return Record.BonusPoints; }
set { Record.BonusPoints = value; }
}
Migratord:
SchemaBuilder.CreateTable("AccountPartRecord",
table => table
.ContentPartRecord()
.Column<Guid>("AccountId",
x => x
.WithType(DbType.Guid)
.Unique()
.NotNull()))
ContentDefinitionManager.AlterPartDefinition("AccountPart",
builder => builder.Attachable());
ContentDefinitionManager.AlterTypeDefinition("User",
cfg => cfg.WithPart("AccountPart"));
Also i've tried to add AccountId this way:
SchemaBuilder.ExecuteSql(#"
ALTER TABLE [BetIt].[dbo].[Betit_AccountPartRecord]
ADD AccountId UNIQUEIDENTIFIER DEFAULT NEWID()");
It behaves the same - sets emty Guid to each new user. But if i open Sql Management Studio an add new record manually it'll generate a random Guid.
I'm completely confused...
Update:
I've actually acheived auto Guid generation for the Content Part by using handlers. But it looks more like workaround to me. I don't belive this is the only way to generate unique value.
Migrators:
SchemaBuilder.CreateTable("AccountPartRecord",
table => table
.ContentPartRecord()
.Column<long>("AccountId",
x => x
.WithType(DbType.Guid)
.NotNull()
.Unique())
Part:
public class AccountPart : ContentPart<AccountPartRecord>
{
public Guid AccountId
{
get { return Record.AccountId; }
set { Record.AccountId = value; }
}
}
Handler:
public class AccountPartHandler : ContentHandler
{
public AccountPartHandler(IRepository<AccountPartRecord> repository)
{
Filters.Add(new ActivatingFilter<AccountPart>("User"));
Filters.Add(StorageFilter.For(repository));
OnCreating<AccountPart>((context, accountPart) =>
accountPart.AccountId = Guid.NewGuid());
}
}
Setting up values through handler is not a workaround and it's actually the preferred way (take a look eg. at how IdentityPart unique identifier is set). All logic should be kept in code, not database (which is just a data store). This means that Guid and/or custom identifier generation should be there as well.
Please note that Orchard always creates an empty record first and then fills it with values. In this case columns with NotNull and/or Unique constraints can cause problems. Try to avoid them.
I have my dynamo db table as follows:
HashKey(xyz) ,RangeKey(timestamp)
Now for each hash key i have set of range key.
Now i want to query based on set of hashkey and i want only most recent value correspoding to that to be fetched .I dont want to do in memory sorting and then picking most recent version.
Can i do this in any way?
Use case is that i will do a bulkget and pass set of hashkey (say 100) , so i want to get one record for each hashkey
You (currently) can't set constraints on a batch get. See http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/API_BatchGetItems.html
However, for single hash keys, you can set the direction using ScanIndexForward. See http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/API_Query.html for information.
Sample java code:
new QueryRequest().withTableName("table-name")
.withScanIndexForward(false)
.withLimit(1)
.withHashKeyValue(new AttributeValue().withS("hash-key"));
It will not be very efficient though, as you will need to make this call 100 times.
Use ScanIndexForward(true for ascending and false for descending) and can also limit the result using setLimit value of Query Expression.
Please find below the code where used QueryPage for finding the single record.
public EventLogEntitySave fetchLatestEvents(String id) {
EventLogEntitySave entity = new EventLogEntitySave();
entity.setId(id);
DynamoDBQueryExpression<EventLogEntitySave> queryExpression = new DynamoDBQueryExpression<EventLogEntitySave>().withHashKeyValues(entity);
queryExpression.setScanIndexForward(false);
queryExpression.withLimit(1);
queryExpression.setLimit(1);
List<EventLogEntitySave> result = dynamoDBMapper.queryPage(EventLogEntitySave.class, queryExpression).getResults();
System.out.println("size of records = "+result.size() );
result.get(0);
}
#DynamoDBTable(tableName = "PROD_EA_Test")
public class EventLogEntitySave {
#DynamoDBHashKey
private String id;
private String reconciliationProcessId;
private String vin;
private String source;
}
public class DynamoDBConfig {
#Bean
public AmazonDynamoDB amazonDynamoDB() {
String accesskey = "";
String secretkey = "";
//
// creating dynamo client
BasicAWSCredentials credentials = new BasicAWSCredentials(accesskey, secretkey);
AmazonDynamoDB dynamo = new AmazonDynamoDBClient(credentials);
dynamo.setRegion(Region.getRegion(Regions.US_WEST_2));
return dynamo;
}
Can I convert a IQueryable result to a injected object on the fly?
I know I can do this with the help of Valueinjecter:
usercategory uc1 = new usercategory(example);
usercategoryViewData ucVD1 = new usercategoryViewData();
ucVD1.injectFrom(uc1);
So instead of this:
from u in db.usercategories
where u.id==id
select new usercategoryViewModel {id = u.id, name = u.id, description = u.id};
I would like to use something like:
from u in db.usercategories
where u.id==id
select new usercategoryViewModel.InjectFrom(u);
The other alternative I have atm is to loop through a IEnumerable and create one with injected objects instead.
here I show 2 ways of doing this:
public class Foo
{
public string Name { get; set; }
}
[Test]
public void TestMethod1()
{
var bars = new[] { new { Name = "aaa" }, new { Name = "bbb" } };
IEnumerable<Foo> foos = bars.Select(o => new Foo().InjectFrom(o)).Cast<Foo>();
IEnumerable<Foo> foos2 = from bar in bars
select new Foo().InjectFrom(bar) as Foo;
Assert.AreEqual(bars.First().Name, foos.First().Name);
Assert.AreEqual(bars.First().Name, foos2.First().Name);
}
Whilst that might be possible, if there's any complexity in u then I think it's a bad idea.
At some point the ORM you're using (Linq-to-SQL? EF?) needs to switch from executing on the database to executing in .NET. At that boundary it needs to work out what data it needs from the database. In the first example, that's completely clear: it only needs u.id. In the second it has no idea: it doesn't know what properties InjectFrom will read from it, so it will need to load all the values from the UserCategories table, and maybe related objects too, just in case.