How to compare the ArrayList Object (java class) in JESS? - jess

This is my main method.
public static void main(String[] args) throws JessException {
Rete engine = new Rete();
engine.batch("template.clp");
PizzaBase pizzaBase = new PizzaBase();
pizzaBase.setSize(9);
PizzaTopping pizzaTopping = new PizzaTopping();
pizzaTopping.setName("T1");
PizzaTopping pizzaTopping2 = new PizzaTopping();
pizzaTopping2.setName("T2");
PizzaTopping pizzaTopping3 = new PizzaTopping();
pizzaTopping3.setName("T3");
List<PizzaTopping> pizzaToppingList = new ArrayList<PizzaTopping>();
pizzaToppingList.add(pizzaTopping);
pizzaToppingList.add(pizzaTopping2);
pizzaToppingList.add(pizzaTopping3);
Pizza pizza = new Pizza();
pizza.setBase(pizzaBase);
pizza.setPizzaToppingList(pizzaToppingList);
engine.add(pizzaBase);
engine.addAll(pizzaToppingList);
engine.add(pizza);
engine.eval("(facts)");
engine.batch("rules.clp");
engine.reset();
engine.run();
engine.eval("(facts)");
}
I would like to check the pizza that contain the topping name is "T2" in the pizzaToppingList or not.The rule is shown below
(defrule rule1
(Pizza (pizzaToppingList ?t2) (OBJECT ?a))
(PizzaTopping (name "T2") (OBJECT ?t2))
=>
(printout t "fired")
)
But It does not work,because In JESS, slot value of pizzaToppingList is ArrayList(java object).Which means the pizzaToppingList slot is not the Lists value in JESS.
How I solve this problem ? thank!

Well, you'll have to call a method of Java's own ArrayList class. A simple way is to use the test CE:
(defrule rule1
(Pizza (pizzaToppingList ?ptList) (OBJECT ?a))
(PizzaTopping (name "T2") (OBJECT ?t2))
(test (?ptList contains ?t2) )
=>
(printout t "fired")
)
What you have tried cannot work, since you are using the same binding variable ?t2 for the list and for what might be one of its elements.

Related

How to render a sorted map in json libraries (of play framework)?

I need to render a sorted map by a user-defined type.
SortedMap[X, Seq[Y]]
Json library should render the map as ordered by the X.name
case class X(order: Int, name: String) extends Ordered[X]
Assume I have X(1, "James"), X(2, "Mel"), X(3, "Ashley").
The output map should be
"James" : Seq(Y)
"Mel" : Seq(Y)
"Ashley": Seq(Y)
The inMap is correctly sorted (as viewed by the debugger), but after the rendering, the sorting order(X.order) is lost. Probably due to the toSeq. Any ideas?
implicit val myWrites = new Writes[SortedMap[X, Seq[Y]]] {
def writes(inMap: SortedMap[X, Seq[Y]]): JsValue =
Json.obj(inMap.map {case (s, o) =>
val r: (String, JsValueWrapper) = s.name() -> Json.toJson(o)
r
}.toSeq:_*)
}
So...
I never meet the word "render" used as "convert to"
ordering by key original key in SortedSet is lost after mapping because you change the key type so the result is ordered by a new key type (here: String)
if you want to preserve the order of items in between mapping I would suggest using ListMap
though in your particular case you can do away with Seq of tuples, as at the end of the day, this is what you need to produce
implicit val myWrites: Writes[SortedMap[X, Seq[Y]]] = new Writes[SortedMap[X, Seq[Y]]] {
def writes(inMap: SortedMap[X, Seq[Y]]): JsValue =
Json.obj(inMap.toSeq.map { case (s, o) =>
s.name() -> Json.toJson(o)
}:_*)
}

How to compare java object in jess

I have a problem when I compare java object as attribute inside the java class
This is my clp file
(import Model.*)
(deftemplate PizzaBase
(declare (from-class PizzaBase)
(include-variables TRUE)))
(deftemplate PizzaTopping
(declare (from-class PizzaTopping)
(include-variables TRUE)))
(deftemplate Pizza
(declare (from-class Pizza)
(include-variables TRUE)))
(defrule make-pizza
?pizzaBase1 <-(PizzaBase{size == 9})
(Pizza(pizzaBase ?pizzaBase1))
=>
(add (new PizzaBase "New DeepPan" 10))
)
According from my rule, I want to create a new pizzaBase.When the pizzaBase object in Pizza equal pizzaBase1(size = 9), but JESS is not create a new fact for me.
From my thinking, I think JESS cannot compare the Java object that create from the class.Therefore, There isn't add any fact to JESS.
So,"How to solve this problem?",because I look on the manual on the JESS website but there aren't any title that according my problem.
Thank!
You may have overlooked section 5.3.2., Adding Java objects to working memory.
A Java object isn't the same as a fact, even when you derive a shadow (!) fact from a POJO, using from-class and include-variables. A fact contains a reference to the Java object you insert by calling (add ?aNewObject) in the reserved slot name OBJECT.
Change your rule like this:
(defrule make-pizza
(PizzaBase{size == 9}(OBJECT ?pizzaBase1))
(Pizza(pizzaBase ?pizzaBase1))
=>
(add (new PizzaBase "New DeepPan" 10))
)

Why does this object need a DataContext?

This is weird.
regiao C = new regiao();
C.Nome = textBoxNome.Text;
C.Descricao = textBoxDescicao.Text;
C.cidades.AddRange(ListaIN);
mgrRegiao mgr = new mgrRegiao();
mgr.UpdateRegiao(C);
C is a Linq object (code generated by VS2008 in the dbml file) the operation is out of any context. ListaIN in is of type List. That is also the type of C.cidades. The call to mgr.UpdateRegiao creates a context, Copies the contents to objects inside the context and updates the objects. Some of the itens in ListN may have come from a Context (from a query result)
When
C.cidades.AddRange(ListaIN)
Executes I get an exception
Cannot access a disposed object.
Object name: 'DataContext accessed after Dispose.'.
at the line
regiao previousValue = this._regiao.Entity;
in the generated code for the entity regiao set opeation.
[Association(Name="regiao_cidade", Storage="_regiao", ThisKey="IDRegiao", IsForeignKey=true)]
public regiao regiao
{
get
{
return this._regiao.Entity;
}
set
{
regiao previousValue = this._regiao.Entity;
if (((previousValue != value)
|| (this._regiao.HasLoadedOrAssignedValue == false)))
{
this.SendPropertyChanging();
if ((previousValue != null))
{
this._regiao.Entity = null;
previousValue.cidades.Remove(this)
...
Whats wrong ? The object C does not have and never had a context. Why it needs a context and how do I solve this ? Is it because some itens in ListaIN came from the database ? If so, is there a way to detach them ?
OK, so that just the way Linq is, i guess.

Unable to create a constant value of type 'T'

I have a table called Subjects,
I have an another Table called Allocations, which stores the Allocations of the Subjects
I have a Datagridview, which is populated with Subject Allocations from the Allocations Table
Now i need to get the Subjects that are not in the Datagridview
To do this
I Get All Subjects from the ObjectContext
Now i get all the Subjects that are alloted from the Datagridview (It Returns me an InMemory Collection)
Now i use the LINQ.EXCEPT method to filter the results, but it is throwing me the Following Exception,
"Unable To Create Constant Value of Type "ObjectContext.Subjects" Only primitive types ('such as Int32, String, and Guid') are supported in this context."
Below is my Code
public static IOrderedQueryable<Subject> GetSubjects()
{
return OBJECTCONTEXT.Subjects.OrderBy(s => s.Name);
}
private IQueryable<Subject> GetAllocatedSubjectsFromGrid()
{
return (from DataGridViewRow setRow in dgv.Rows
where !setRow.IsNewRow
select setRow.DataBoundItem).Cast<Allocation>() //I know the Problem lies somewhere in this Function
.Select(alloc =>alloc.Subject).AsQueryable();
}
private void RUN()
{
IQueryable<Subject> AllSubjects = GetSubjects(); //Gets
IQueryable<Subject> SubjectsToExclude = GetAllocatedSubjectsFromGrid();
IQueryable<Subject> ExcludedSubjects = AllSubjects.Except(SubjectsToExclude.AsEnumerable());
//Throwing Me "Unable to create a constant value of type 'OBJECTCONTEXT.Subject'. Only primitive types ('such as Int32, String, and Guid') are supported in this context."
}
As a result of googling i found that it happens because LINQ can't compare between InMemory collection(Records from DGV) and Objectcontext(FromDB)
A little short of time, have not tested it. But I guess you can try to get it all in memory. So instead of using
IQueryable<Subject> AllSubjects = GetSubjects(); //Gets
You do
List<Subject> AllSubjects = GetSubjects().ToList(); //
List<Subject> SubjectsToExclude = GetAllocatedSubjectsFromGrid().ToList();
List<Subject> ExcludedSubjects = AllSubjects.Except(SubjectsToExclude);
I got around this by comparing keys in a Where clause rather than using Except.
So instead of:
var SubjectsToExclude = GetAllocatedSubjectsFromGrid();
var ExcludedSubjects = AllSubjects.Except(SubjectsToExclude.AsEnumerable());
Something more like:
var subjectsToExcludeKeys =
GetAllocatedSubjectsFromGrid()
.Select(subject => subject.ID);
var excludedSubjects =
AllSubjects
.Where(subject => !subjectsToExcludeKeys.Contains(subject.ID));
(I'm guessing what your entity's key looks like though.)
This allows you to keep everything in Entity Framework, rather than pulling everything into memory.

Explicit construction of entity type '###' in query is not allowed.

Using Linq commands and Linq To SQL datacontext, Im trying to instance an Entity called "Produccion" from my datacontext in this way:
Demo.View.Data.PRODUCCION pocoProduccion =
(
from m in db.MEDICOXPROMOTORs
join a in db.ATENCIONs on m.cmp equals a.cmp
join e in db.EXAMENXATENCIONs on a.numeroatencion equals e.numeroatencion
join c in db.CITAs on e.numerocita equals c.numerocita
where e.codigo == codigoExamenxAtencion
select new Demo.View.Data.PRODUCCION
{
cmp = a.cmp,
bonificacion = comi,
valorventa = precioEstudio,
codigoestudio = lblCodigoEstudio.Content.ToString(),
codigopaciente = Convert.ToInt32(lblCodigoPaciente.Content.ToString()),
codigoproduccion = Convert.ToInt32(lblNroInforme.Content.ToString()),
codigopromotor = m.codigopromotor,
fecha = Convert.ToDateTime(DateTime.Today.ToShortDateString()),
numeroinforme = Convert.ToInt32(lblNroInforme.Content.ToString()),
revisado = false,
codigozona = (c.codigozona.Value == null ? Convert.ToInt32(c.codigozona) : 0),
codigoclinica = Convert.ToInt32(c.codigoclinica),
codigoclase = e.codigoclase,
}
).FirstOrDefault();
While executing the above code, I'm getting the following error that the stack trace is included:
System.NotSupportedException was caught
Message="The explicit construction of the entity type 'Demo.View.Data.PRODUCCION' in a query is not allowed."
Source="System.Data.Linq"
StackTrace:
en System.Data.Linq.SqlClient.QueryConverter.VisitMemberInit(MemberInitExpression init)
en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.Visit(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.VisitSelect(Expression sequence, LambdaExpression selector)
en System.Data.Linq.SqlClient.QueryConverter.VisitSequenceOperatorCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitMethodCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.Visit(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.VisitFirst(Expression sequence, LambdaExpression lambda, Boolean isFirst)
en System.Data.Linq.SqlClient.QueryConverter.VisitSequenceOperatorCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitMethodCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.ConvertOuter(Expression node)
en System.Data.Linq.SqlClient.SqlProvider.BuildQuery(Expression query, SqlNodeAnnotations annotations)
en System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
en System.Data.Linq.DataQuery`1.System.Linq.IQueryProvider.Execute[S](Expression expression)
en System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
en Demo.View.InformeMedico.realizarProduccionInforme(Int32 codigoExamenxAtencion, Double precioEstudio, Int32 comi) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 602
en Demo.View.InformeMedico.UpdateEstadoEstudio(Int32 codigo, Char state) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 591
en Demo.View.InformeMedico.btnGuardar_Click(Object sender, RoutedEventArgs e) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 683
InnerException:
Is that now allowed in LINQ2SQL?
Entities can be created outside of queries and inserted into the data store using a DataContext. You can then retrieve them using queries. However, you can't create entities as part of a query.
I am finding this limitation to be very annoying, and going against the common trend of not using SELECT * in queries.
Still with c# anonymous types there is a workaround, by fetching the objects into an anonymous type, and then copy it over into the correct type.
For example:
var q = from emp in employees where emp.ID !=0
select new {Name = emp.First + " " + emp.Last, EmployeeId = emp.ID }
var r = q.ToList();
List<User> users = new List<User>(r.Select(new User
{
Name = r.Name,
EmployeeId = r.EmployeeId
}));
And in the case when we deal with a single value (as in the situation described in the question) it is even easier, and we just need to copy directly the values:
var q = from emp in employees where emp.ID !=0
select new { Name = emp.First + " " + emp.Last, EmployeeId = emp.ID }
var r = q.FirstOrDefault();
User user = new User { Name = r.Name, EmployeeId = r.ID };
If the name of the properties match the database columns we can do it even simpler in the query, by doing select
var q = from emp in employees where emp.ID !=0
select new { emp.First, emp.Last, emp.ID }
One might go ahead and write a lambda expression that can copy automatically based on the property name, without needing to specify the values explictly.
Here's another workaround:
Make a class that derives from your LINQ to SQL class. I'm assuming that the L2S class that you want to return is Order:
internal class OrderView : Order { }
Now write the query this way:
var query = from o in db.Order
select new OrderView // instead of Order
{
OrderID = o.OrderID,
OrderDate = o.OrderDate,
// etc.
};
Cast the result back into Order, like this:
return query.Cast<Order>().ToList(); // or .FirstOrDefault()
(or use something more sensible, like BLToolkit / LINQ to DB)
Note: I haven't tested to see if tracking works or not; it works to retrieve data, which is what I needed.
I have found that if you do a .ToList() on the query before trying to contruct new objects it works
I just ran into the same issue.
I found a very easy solution.
var a = att as Attachment;
Func<Culture, AttachmentCulture> make =
c => new AttachmentCulture { Culture = c };
var culs = from c in dc.Cultures
let ac = c.AttachmentCultures.SingleOrDefault(
x => x.Attachment == a)
select ac == null ? make(c) : ac;
return culs;
I construct an anonymous type, use IEnumerable (which preserves deferred execution), and then re-consruct the datacontext object. Both Employee and Manager are datacontext objects:
var q = dc.Employees.Where(p => p.IsManager == 1)
.Select(p => new { Id = p.Id, Name = p.Name })
.AsEnumerable()
.Select(item => new Manager() { Id = item.Id, Name = item.Name });
Within the book "70-515 Web Applications Development with Microsoft .NET Framework 4 - Self paced training kit", page 638 has the following example to output results to a strongly typed object:
IEnumerable<User> users = from emp in employees where emp.ID !=0
select new User
{
Name = emp.First + " " + emp.Last,
EmployeeId = emp.ID
}
Mark Pecks advice appears to contradict this book - however, for me this example still displays the above error as well, leaving me somewhat confused. Is this linked to version differences? Any suggestions welcome.
I found another workaround for the problem that even lets you retain your result as IQueryale, so it doesn't actually execute the query until you want it to be executed (like it would with the ToList() method).
So linq doesn't allow you to create an entity as a part of query? You can shift that task to the database itself and create a function that will grab the data you want. After you import the function to your data context, you just need to set the result type to the one you want.
I found out about this when I had to write a piece of code that would produce a IQueryable<T> in which the items don't actually exist in the table containing T.
pbz posted a work around by creating a View class inherited from an entity class that you could be working with. I'm working with a dbml model of a table that has > 200 columns. When I try and return the whole table I get "Root Element missing" errors. I couldn't find anyone who wanted to deal with my particular issue so I was looking at rewriting my entire approach. Just creating a view class for the entitiy class worked in my case.
As pbz suggests : Create a view class that inherits from your entity class. For me this is tbCamp so :
internal class tbCampView : tbCamp
{
}
Then use the view class in your query :
using (var dc = ConnectionClass.Connect(Dev))
{
var camps = dc.tbCamps.Select(s => new tbCampView
{
active = s.active,
idCamp = s.idCamp,
campName = s.campName
});
SmartTableViewer(camps, dg1);
}
private void SmartTableViewer<T>(IEnumerable<T> allRecords)
{
// Build sorted rows back into new table
var table = new DataTable();
// Create columns based on type
if (allRecords is IEnumerable<tbCamp> tbCampRecords)
{
// Get the columns you want
table.Columns.Add("idCamp");
table.Columns.Add("campName");
foreach (var record in tbCampRecords)
{
// Make a new row
var r = table.NewRow();
// Add the contents to each column of the row
r["idCamp"] = record.idCamp;
r["campName"] = record.campName;
// Add the row to the table.
table.Rows.Add(r);
}
}
else
{
MessageBox.Show("Unhandled type. Add support for new data type in SmartTableViewer()");
return;
}
// Update table in grid
dg1.DataSource = table.DefaultView;
}
Here is what happens when you try and create an entity class object in the query.
I didn't want to have to use an anonymous type if I could help it because I wanted the type to be tbCamp. Since tbCampView is of type tbCamp the is operator works well. see Brian Hasden's answer Passing a generic List<> in C#
I'm surprised this is even an issue but with larger tables I run into this error so I thought I would just show it here :
When trying to read this table into memory I get the following error. There are < 2000 rows but the columns are > 200 for each. I don't know if that is an issue or not.
If I just want a few columns I need to create a custom class and handle that which isn't that big of a pain. With the approach pbz provided I don't have to worry about it.
Here is the entire project in case it helps someone.
public partial class Form1 : Form
{
private const bool Dev = true;
public Form1()
{
InitializeComponent();
}
private void btnGetAllCamps_Click(object sender, EventArgs e)
{
using (var dc = ConnectionClass.Connect(Dev))
{
IQueryable<tbCampView> camps = dc.tbCamps.Select(s => new tbCampView
{
// Project columns as needed.
active = s.active,
idCamp = s.idCamp,
campName = s.campName
});
// pass in as a
SmartTableViewer(camps);
}
}
private void SmartTableViewer<T>(IEnumerable<T> allRecords)
{
// Build sorted rows back into new table
var table = new DataTable();
// Create columns based on type
if (allRecords is IEnumerable<tbCamp> tbCampRecords)
{
// Get the columns you want
table.Columns.Add("idCamp");
table.Columns.Add("campName");
foreach (var record in tbCampRecords)
{
//var newRecord = record;
// Make a new row
var r = table.NewRow();
// Add the contents to each column of the row
r["idCamp"] = record.idCamp;
r["campName"] = record.campName;
// Add the row to the table.
table.Rows.Add(r);
}
}
else
{
MessageBox.Show("Unhandled type. Add support for new data type in SmartTableViewer()");
return;
}
// Update table in grid
dg1.DataSource = table.DefaultView;
}
internal class tbCampView : tbCamp
{
}
}